#if ((FEATURE_MODE == 2) || (FEATURE_MODE == 0))

/**
 @file sys_usw_ipuc.c

 @date 2011-11-30

 @version v2.0

 The file contains all ipuc related function
*/

/****************************************************************************
 *
* Header Files
*
****************************************************************************/

#include "ctc_const.h"
#include "ctc_error.h"
#include "ctc_ipuc.h"
#include "ctc_parser.h"
#include "ctc_debug.h"
#include "ctc_packet.h"
#include "ctc_pdu.h"

#include "sys_usw_common.h"
#include "sys_usw_ofb.h"
#include "sys_usw_ftm.h"
#include "sys_usw_rpf_spool.h"
#include "sys_usw_ipuc.h"
#include "sys_usw_ip_tunnel.h"
#include "sys_duet2_calpm.h"
#include "sys_usw_register.h"
#include "sys_usw_stats_api.h"
#include "sys_usw_wb_common.h"
#include "tsingma/sys_tsingma_ipuc_tcam.h"
#include "tsingma/sys_tsingma_nalpm.h"
#include "arctic/sys_nalpm2.h"
#include "sys_usw_xdata_api.h"
#include "sys_usw_l3if.h"

#include "usw/include/drv_ftm.h"
#include "usw/include/drv_common.h"
#include "ctc_avl_tree.h"
#include "sys_usw_nexthop_api.h"
/****************************************************************************
 *
* Defines and Macros
*
*****************************************************************************/
typedef uint32 (* updateIpDa_fn ) (uint8 lchip, void* data, void* change_nh_param);
#define SYS_IPUC_PENDING_NUM 16384
#define SYS_IPUC_PENDING_BLOCK_NUM 16


extern sys_ip_tunnel_master_t* p_usw_ip_tunnel_master[];
extern sys_nalpm_master_t* g_sys_nalpm_master[];


#define SYS_IPUC_MASK_LEN 5
#define SYS_IPUC_L4PORT_LEN 7

#define SYS_IPUC_XDATA_TRUNK0(offset, width)       ((offset + width-1) < 68 && offset >= 64)  /*Nibbl[4]*/
#define SYS_IPUC_XDATA_TRUNK1(offset, width)       ((offset + width-1) < 64 && offset >= 48)  /*Nibbl[3-0]*/
#define SYS_IPUC_XDATA_TRUNK2(offset, width)       ((offset + width-1) < 48 && offset >= 32)  /*Bytel[1-0]*/
#define SYS_IPUC_XDATA_TRUNK3(offset, width)       ((offset + width-1) < 16 && offset >= 0)   /*Not support*/

struct sys_ipuc_ad_node_s
{
    ctc_list_pointer_node_t head;
    ctc_list_pointer_node_t nhid_list_head;
    uint32  ad_index;
    uint32  ldp;
    uint32  overlay_nh;
};
typedef struct sys_ipuc_ad_node_s sys_ipuc_ad_node_t;
/****************************************************************************
 *
* Global and Declaration
*
*****************************************************************************/
sys_ipuc_master_t* p_usw_ipuc_master[CTC_MAX_LOCAL_CHIP_NUM_PP] = {NULL};

#define SYS_LIST_LOCK \
    if(p_usw_ipuc_master[lchip]->lpm_mutex) sal_mutex_lock(p_usw_ipuc_master[lchip]->lpm_mutex)

#define SYS_LIST_UNLOCK \
    if(p_usw_ipuc_master[lchip]->lpm_mutex) sal_mutex_unlock(p_usw_ipuc_master[lchip]->lpm_mutex)

#define CTC_ERROR_RETURN_IPUC_UNLOCK(op) \
    do \
    { \
        int32 rv = (op); \
        if (rv < 0) \
        { \
            sal_mutex_unlock(p_usw_ipuc_master[lchip]->mutex); \
            return (rv); \
        } \
    } while (0)

#define CTC_RETURN_IPUC_UNLOCK(op) \
    do \
    { \
        sal_mutex_unlock(p_usw_ipuc_master[lchip]->mutex); \
        return (op); \
    } while (0)

#define SYS_IP_CHECK_VERSION_ENABLE(ver)                        \
    {                                                               \
        if ((!p_usw_ipuc_master[lchip]) || !p_usw_ipuc_master[lchip]->version_en[ver])     \
        {                                                           \
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [IPUC] SDK is not assigned resource for this version \n");\
			return CTC_E_NOT_READY;\
        }                                                           \
    }

#define ROT(x, k) (((x) << (k)) | ((x) >> (32 - (k))))

#define MIX(a, b, c) \
    do \
    { \
        a -= c;  a ^= ROT(c, 4);  c += b; \
        b -= a;  b ^= ROT(a, 6);  a += c; \
        c -= b;  c ^= ROT(b, 8);  b += a; \
        a -= c;  a ^= ROT(c, 16);  c += b; \
        b -= a;  b ^= ROT(a, 19);  a += c; \
        c -= b;  c ^= ROT(b, 4);  b += a; \
    } while (0)

#define FINAL(a, b, c) \
    { \
        c ^= b; c -= ROT(b, 14); \
        a ^= c; a -= ROT(c, 11); \
        b ^= a; b -= ROT(a, 25); \
        c ^= b; c -= ROT(b, 16); \
        a ^= c; a -= ROT(c, 4);  \
        b ^= a; b -= ROT(a, 14); \
        c ^= b; c -= ROT(b, 24); \
    }

#define IPUC_GEN_IP_STR(buf, ip_ver, ip, mask) do{\
    char buf2[SYS_IPUC_MASK_LEN] = {0};\
    sal_sprintf(buf2, "/%d", mask);\
    if(ip_ver == CTC_IP_VER_4)\
    {\
        uint32 tempip = sal_ntohl(ip[0]);\
        sal_inet_ntop(AF_INET, &tempip, buf, CTC_IPV6_ADDR_STR_LEN);\
        sal_strncat(buf, buf2, 5);\
    }\
    else\
    {\
    uint32 ipv6_address[4] = {0, 0, 0, 0};\
    ipv6_address[0] = sal_ntohl(ip[3]);\
    ipv6_address[1] = sal_ntohl(ip[2]);\
    ipv6_address[2] = sal_ntohl(ip[1]);\
    ipv6_address[3] = sal_ntohl(ip[0]);\
    sal_inet_ntop(AF_INET6, ipv6_address, buf, CTC_IPV6_ADDR_STR_LEN);\
    sal_strncat(buf, buf2, 5);\
    }\
}while(0);

#define WAIT_LOOP 2000
#define VRF_MAP_DEST_MAP_BASE 100
#define SYS_USW_IPUC_HASH_NUM ((SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_HOST)+SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_LPM))/SYS_HASH_SIZE_COMPRESS_RATE_2)
#define SYS_USW_IPUC_NHID_HASH_SIZE 65536

/****************************************************************************
 *
* Function
*
*****************************************************************************/

extern int32
sys_usw_ipuc_update_ipda(uint8 lchip, void* data, void* change_nh_param);

void
sys_usw_ipuc_update_route_stats(uint8 lchip, uint8 ip_ver, sys_ipuc_route_stats_t type, uint8 opt);

int32
sys_usw_ipuc_add(uint8 lchip, ctc_ipuc_param_t* p_ctc_param_info);

int32
sys_usw_ipuc_remove(uint8 lchip, ctc_ipuc_param_t* p_ctc_param_info);

int32
sys_usw_ipuc_update_ldp_dsip(uint8 lchip, sys_com_ldp_update_t* p_param);

int32
sys_usw_ipuc_update_dsip_by_nhid(uint8 lchip, sys_com_ldp_update_t* p_param);

int32
_sys_usw_ipuc_bind_nexthop(uint8 lchip, sys_ipuc_param_t* p_sys_param, uint8 is_bind);

int32
_sys_usw_ipuc_xdata_mapping(ctc_xdata_t* p_xdata, sys_ipuc_xdata_info_t* p_xdata_info, uint8 is_get);

int32
_sys_usw_ipuc_get_xdata_withcheck(uint8 lchip,ctc_xdata_t* p_xdata ,sys_ipuc_xdata_info_t* p_xdata_info ,DsIpDa_m* p_dsipda,uint8 is_check);

int32
_sys_usw_ipuc_add_default_entry(uint8 lchip, uint8 ip_ver, uint16 vrfid, uint32 nh_id, uint8 by_user);

extern int32
_sys_usw_ipuc_process_hash_key(uint8 lchip, sys_ipuc_param_t* p_sys_param, sys_ipuc_opt_type_t opt);

#define __TCAM_API___

int32
sys_usw_ipuc_add_tcam(uint8 lchip, sys_ipuc_param_t *p_sys_param);

int32
sys_usw_ipuc_del_tcam(uint8 lchip, sys_ipuc_param_t *p_sys_param);

int32
sys_usw_ipuc_update_tcam(uint8 lchip, sys_ipuc_param_t *p_sys_param);

#define ___________IPUC_INNER_FUNCTION________________________
#define __1_CALLBACK__

/**
 @brief function of make hash key for ipuc table

 @param[in] p_ipuc_info, information should be maintained for ipuc

 @return CTC_E_XXX
 */
STATIC uint32
_sys_usw_ipv4_hash_make(sys_ipuc_info_t* p_ipuc_info)
{
    uint32 a, b, c;

    /* Set up the internal state */
    a = b = c = 0xdeadbeef + (((uint32)96) << 2);

    a += p_ipuc_info->ip.ipv4;
    b += p_ipuc_info->vrf_id;
    b += (p_ipuc_info->masklen << 16);

    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NAPT))
    {
        b += (p_ipuc_info->l4_dst_port);
        c += CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_TCP_PORT);
    }

    MIX(a, b, c);

    return (c);
}



STATIC uint32
_sys_usw_ipv6_hash_make(sys_ipuc_info_t* p_ipuc_info)
{
    uint32 a, b, c;

    /* Set up the internal state */
    a = b = c = 0xdeadbeef + (((uint32)192) << 2);

    a += p_ipuc_info->ip.ipv6[0];
    b += p_ipuc_info->ip.ipv6[1];
    c += p_ipuc_info->ip.ipv6[2];
    MIX(a, b, c);

    a += p_ipuc_info->ip.ipv6[3];
    b += p_ipuc_info->vrf_id;
    b += (p_ipuc_info->masklen << 16);
    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NAPT))
    {
        b += (p_ipuc_info->l4_dst_port);
        c += CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_TCP_PORT);
    }
    MIX(a, b, c);

    FINAL(a, b, c);

    return (c);
}

STATIC bool
_sys_usw_ipv4_hash_cmp(sys_ipuc_info_t* p_ipuc_info1, sys_ipuc_info_t* p_ipuc_info)
{
    if (p_ipuc_info1->vrf_id != p_ipuc_info->vrf_id)
    {
        return FALSE;
    }

    if (p_ipuc_info1->masklen != p_ipuc_info->masklen)
    {
        return FALSE;
    }

    if (p_ipuc_info1->ip.ipv4 != p_ipuc_info->ip.ipv4)
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_NAPT)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_NAPT))
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_NAPT) &&
            p_ipuc_info1->l4_dst_port != p_ipuc_info->l4_dst_port)
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_IS_TCP_PORT)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_IS_TCP_PORT))
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_HOST_USE_LPM)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_HOST_USE_LPM))
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_PUBLIC_ROUTE)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_PUBLIC_ROUTE))
    {
        return FALSE;
    }

    return TRUE;
}

STATIC bool
_sys_usw_ipv6_hash_cmp(sys_ipuc_info_t* p_ipuc_info1, sys_ipuc_info_t* p_ipuc_info)
{
    if (p_ipuc_info1->vrf_id != p_ipuc_info->vrf_id)
    {
        return FALSE;
    }

    if (p_ipuc_info1->masklen != p_ipuc_info->masklen)
    {
        return FALSE;
    }

    if (p_ipuc_info1->ip.ipv6[3] != p_ipuc_info->ip.ipv6[3])
    {
        return FALSE;
    }

    if (p_ipuc_info1->ip.ipv6[2] != p_ipuc_info->ip.ipv6[2])
    {
        return FALSE;
    }

    if (p_ipuc_info1->ip.ipv6[1] != p_ipuc_info->ip.ipv6[1])
    {
        return FALSE;
    }

    if (p_ipuc_info1->ip.ipv6[0] != p_ipuc_info->ip.ipv6[0])
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_NAPT)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_NAPT))
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_NAPT) &&
        p_ipuc_info1->l4_dst_port != p_ipuc_info->l4_dst_port)
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_IS_TCP_PORT)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_IS_TCP_PORT))
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_HOST_USE_LPM)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_HOST_USE_LPM))
    {
        return FALSE;
    }

    if ((p_ipuc_info1->route_flag & SYS_IPUC_FLAG_PUBLIC_ROUTE)
        != (p_ipuc_info->route_flag & SYS_IPUC_FLAG_PUBLIC_ROUTE))
    {
        return FALSE;
    }

    return TRUE;
}
STATIC uint32
_sys_usw_ad_hash_make(sys_ipuc_ad_node_t* p_ad_node)
{
    return ctc_hash_caculate(sizeof(uint32), &p_ad_node->ad_index);
}
STATIC bool

_sys_usw_ad_hash_cmp(sys_ipuc_ad_node_t* p_ad_node1, sys_ipuc_ad_node_t* p_ad_node2)
{
    if(p_ad_node1->ad_index != p_ad_node2->ad_index)
    {
        return FALSE;
    }
    return TRUE;
}

STATIC uint32
_sys_usw_ipuc_ad_profile_make(sys_ipuc_ad_spool_t* p_ipuc_ad)
{
    uint32 a, b, c;
    uint32* k = (uint32*)p_ipuc_ad->param.p_ad;
    uint8   length = TABLE_ENTRY_SIZE(p_ipuc_ad->param.lchip, DsIpDa_t);

    /* Set up the internal state */
    a = b = c = 0xdeadbeef;

    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
    while (length > 12)
    {
        a += k[0];
        b += k[1];
        c += k[2];
        MIX(a, b, c);
        length -= 12;
        k += 3;
    }

    a += k[0];

    FINAL(a, b, c);
    return c;
}

STATIC bool
_sys_usw_ipuc_ad_profile_cmp(sys_ipuc_ad_spool_t* p_bucket, sys_ipuc_ad_spool_t* p_new)
{
    DsIpDa_m dsipda;
    uint32 cmd = 0;
    uint8 lchip = 0;
    if (!p_bucket || !p_new)
    {
        return FALSE;
    }
    if (IPUC_AD_SPOOL_INVALID_IDX == p_bucket->ad_index)  /*for spool add error rollback*/
    {
        return TRUE;
    }
    lchip = p_new->param.lchip;

    cmd = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, p_bucket->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);
    if (sal_memcmp (&dsipda, p_new->param.p_ad, TABLE_ENTRY_SIZE(p_new->param.lchip, DsIpDa_t)))
    {
        return FALSE;
    }
    p_new->param.dsipda_built = 1;
    return TRUE;
}
STATIC int32
_sys_usw_ipuc_ad_profile_build_index(sys_ipuc_ad_spool_t* p_bucket, void* user_param)
{
    sys_ipuc_ad_node_t* p_ad_node;
    int32 ret = 0;
    uint32 value_32 = 0;
    uint32 overlay_nhid = ((sys_ipuc_ad_spool_param_t*)user_param)->overlay_nh;
    uint32 ldp = ((sys_ipuc_ad_spool_param_t*)user_param)->ldp;
    uint8  lchip = ((sys_ipuc_ad_spool_param_t*)user_param)->lchip;
    uint8 loop_lchip = 0;

    if ((CTC_WB_STATUS(lchip) != CTC_WB_STATUS_RELOADING))
    {
        ret = sys_usw_ftm_alloc_table_offset(lchip, DsIpDa_t, 1, 1, 1, &value_32);
        if(ret)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "spool alloc index failed,  line=%d\n",__LINE__);
            p_bucket->ad_index = IPUC_AD_SPOOL_INVALID_IDX;     /*spool alloc index failed, return invalid ad_index*/
            return ret;
        }
        for(loop_lchip = 1;loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt;loop_lchip++)
        {
            CTC_ERROR_GOTO(sys_usw_ftm_alloc_table_offset_from_position(lchip + (loop_lchip * SYS_PP_NUM(lchip)), DsIpDa_t, 1, 1, value_32), ret, error0);
        }
        p_bucket->ad_index = value_32;
    }
    else
    {
        DO_SLAVE_LOOP_START
        CTC_ERROR_GOTO(sys_usw_ftm_alloc_table_offset_from_position(lchip + (loop_lchip * SYS_PP_NUM(lchip)), DsIpDa_t, 1, 1, p_bucket->ad_index), ret, error0);
        DO_SLAVE_LOOP_END
    }

    /*For TM.MX overlay update ldp, build another node*/
    if(!ldp && !overlay_nhid)
    {
        return CTC_E_NONE;
    }

    if(NULL == (p_ad_node = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_ipuc_ad_node_t))))
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_ad_node, 0, sizeof(sys_ipuc_ad_node_t));
    p_ad_node->ad_index = p_bucket->ad_index;
    p_ad_node->ldp = ldp;
    p_ad_node->overlay_nh = overlay_nhid;
    if(NULL == ctc_hash_insert(p_usw_ipuc_master[lchip]->ad_hash, p_ad_node))
    {
        return CTC_E_NO_MEMORY;
    }
    if (ldp)
    {
        CTC_BIT_SET(p_bucket->flag, 0);
        sys_usw_add_ldp_node(lchip, p_usw_ipuc_master[lchip]->ldp_hash, ldp, &p_ad_node->head);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "add l3 dsip %d to ldp %d\n", p_bucket->ad_index , ldp);
    }

    if (overlay_nhid)
    {
        CTC_BIT_SET(p_bucket->flag, 1);
        sys_usw_add_ldp_node(lchip, p_usw_ipuc_master[lchip]->nhid_hash, overlay_nhid, &p_ad_node->nhid_list_head);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "add l3 dsip %d to nhid %d\n", p_bucket->ad_index , overlay_nhid);
    }
    return CTC_E_NONE;

error0:
    p_bucket->ad_index = IPUC_AD_SPOOL_INVALID_IDX;
    if(loop_lchip !=0 && loop_lchip != p_usw_ipuc_master[lchip]->slave_lchip_cnt)
    {
        do
        {
            loop_lchip--;
            sys_usw_ftm_free_table_offset(lchip + (loop_lchip * SYS_PP_NUM(lchip)), DsIpDa_t, 0, 1, value_32);

        } while (loop_lchip > 0);
    }
    return ret;
}

STATIC int32
_sys_usw_ipuc_ad_profile_free_index(sys_ipuc_ad_spool_t* p_bucket, void* user_param)
{
    sys_ipuc_ad_node_t  temp_node;
    sys_ipuc_ad_node_t* p_ad_node;
    uint8  lchip = ((sys_ipuc_ad_spool_param_t*)user_param)->lchip;
    uint8 loop_lchip = 0;

    DO_SLAVE_LOOP_START
    CTC_ERROR_DUMP(sys_usw_ftm_free_table_offset(lchip + (loop_lchip * SYS_PP_NUM(lchip)), DsIpDa_t, 0, 1, p_bucket->ad_index));
    DO_SLAVE_LOOP_END

    if(!p_bucket->flag)
    {
        return CTC_E_NONE;
    }
    temp_node.ad_index = p_bucket->ad_index;
    if(NULL == (p_ad_node = ctc_hash_lookup(p_usw_ipuc_master[lchip]->ad_hash, &temp_node)))
    {
        return CTC_E_NONE;
    }

    /*For TM.MX overlay update ldp, build another node*/
    if (p_ad_node->ldp)
    {
        sys_usw_remove_ldp_node(lchip, p_usw_ipuc_master[lchip]->ldp_hash, p_ad_node->ldp, &p_ad_node->head);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "remove l3 dsip %d from ldp %d\n", p_bucket->ad_index , p_ad_node->ldp);
    }

    if (p_ad_node->overlay_nh)
    {
        sys_usw_remove_ldp_node(lchip, p_usw_ipuc_master[lchip]->nhid_hash, p_ad_node->overlay_nh, &p_ad_node->nhid_list_head);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "remove l3 dsip %u from nhid %u\n", p_bucket->ad_index, p_ad_node->overlay_nh);
    }

    ctc_hash_remove(p_usw_ipuc_master[lchip]->ad_hash, p_ad_node);
    mem_free(p_ad_node);
    return CTC_E_NONE;
}

#ifdef CTC_WB_RT_SYNC
STATIC int32
_sys_usw_ipuc_warmboot_hash_traverse_remove(sys_ipuc_info_t* old_node, void* user_data)
{
    return 1;
}

uint32 
_sys_usw_ipuc_update_hash(uint8 lchip)
{
    ctc_wb_query_t wb_query;
    sys_ipuc_info_t *p_ipuc_info;
    uint32 entry_cnt = 0;
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = CTC_IP_VER_4;

    if (!CTC_WB_ENABLE(lchip)||(!ctc_wb_get_rt_en(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO)))
    {
        return CTC_E_NONE;
    }

    ctc_hash_traverse_remove(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_4], (hash_traversal_fn)_sys_usw_ipuc_warmboot_hash_traverse_remove, NULL);
    ctc_hash_traverse_remove(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_6], (hash_traversal_fn)_sys_usw_ipuc_warmboot_hash_traverse_remove, NULL);
    CTC_WB_INIT_QUERY_T((&wb_query),sys_wb_ipuc_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO);
    CTC_WB_QUERY_ENTRY_BEGIN2((&wb_query));
        p_ipuc_info = (sys_ipuc_info_t *)wb_query.buffer + entry_cnt;
        ip_ver = CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_IPV6) ? CTC_IP_VER_6 : CTC_IP_VER_4;
        ctc_hash_insert(p_usw_ipuc_master[lchip]->fib_hash[ip_ver], p_ipuc_info);
    CTC_WB_QUERY_ENTRY_END2((&wb_query));

done:
    return ret;
}
#endif

#define __2_OPERATE_DB__



STATIC void
_sys_usw_ipuc_param_to_info(uint8 lchip, ctc_ipuc_param_t *p_ctc_param, sys_ipuc_info_t *p_ipuc_info)
{
    uint32 route_flag = 0;
    uint8 addr_size = 0;

    if ( CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_MERGE_KEY))
    {
        CTC_SET_FLAG(route_flag, SYS_IPUC_FLAG_MERGE_KEY);
    }
    if ( CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT))
    {
        CTC_SET_FLAG(route_flag, SYS_IPUC_FLAG_HASH_CONFLICT);
    }
    if(p_usw_ipuc_master[lchip]->default_route_mode && 0 == p_ctc_param->masklen)
    {
        CTC_SET_FLAG(route_flag, SYS_IPUC_FLAG_DEFAULT);
    }

    addr_size = (p_ctc_param->ip_ver == CTC_IP_VER_4) ? sizeof(ip_addr_t) : sizeof(ipv6_addr_t);

    if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_PUBLIC_ROUTE))
    {
        p_ipuc_info->vrf_id = 0;
    }
    else
    {
        p_ipuc_info->vrf_id = p_ctc_param->vrf_id;
    }
    p_ipuc_info->masklen = p_ctc_param->masklen;

    p_ipuc_info->l4_dst_port = 0;
    if(p_ctc_param->l4_dst_port)
    {
        CTC_SET_FLAG(route_flag, SYS_IPUC_FLAG_NAPT);
        p_ipuc_info->l4_dst_port = p_ctc_param->l4_dst_port;
    }

    sal_memcpy(&(p_ipuc_info->ip), &(p_ctc_param->ip), addr_size);

    p_ipuc_info->route_flag = route_flag;
    SYS_IPUC_CTC2SYS_FLAG_CONVERT(p_ctc_param->route_flag, p_ipuc_info->route_flag);
    if (p_ctc_param->l4_dst_port && p_ctc_param->is_tcp_port)
    {
        CTC_SET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_TCP_PORT);
    }

    if (p_ctc_param->ip_ver == CTC_IP_VER_6)
    {
        CTC_SET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_IPV6);
    }

    if ((DRV_IS_AT(lchip)) && p_ctc_param->xdata)
    {
        CTC_SET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_XDATA);
    }

    p_ipuc_info->nh_id = p_ctc_param->nh_id;

    return;
}

STATIC void
_sys_usw_ipuc_info_to_param(uint8 lchip, ctc_ipuc_param_t *p_ctc_param, sys_ipuc_info_t *p_ipuc_info)
{
    uint8 addr_size = 0;

    sal_memset(p_ctc_param, 0, sizeof(ctc_ipuc_param_t));

    addr_size = (SYS_IPUC_VER(p_ipuc_info) == CTC_IP_VER_4) ? sizeof(ip_addr_t) : sizeof(ipv6_addr_t);
    sal_memcpy(&(p_ctc_param->ip), &(p_ipuc_info->ip), addr_size);

    p_ctc_param->ip_ver = SYS_IPUC_VER(p_ipuc_info);
    p_ctc_param->vrf_id = p_ipuc_info->vrf_id;
    p_ctc_param->masklen = p_ipuc_info->masklen;

    p_ctc_param->l4_dst_port = CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NAPT) ? p_ipuc_info->l4_dst_port : 0;
    p_ctc_param->nh_id = p_ipuc_info->nh_id;

    SYS_IPUC_SYS2CTC_FLAG_CONVERT(p_ctc_param->route_flag, p_ipuc_info->route_flag);

    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_TCP_PORT))
    {
        p_ctc_param->is_tcp_port = 1;
    }

    return;
}

STATIC int32
_sys_usw_ipuc_db_get_info_cb(void* p_data_o, void* p_data_m)
{
    sys_ipuc_traverse_t* trav_data = (sys_ipuc_traverse_t*)p_data_m;
    sys_ipuc_param_list_t* p_param_list = (sys_ipuc_param_list_t*)(trav_data->data1);
    sys_ipuc_info_t* p_ipuc_info = (sys_ipuc_info_t*)p_data_o;
    uint8 lchip = trav_data->lchip;

    if (p_ipuc_info->route_opt != DO_ALPM)
    {
        return CTC_E_NONE;
    }

    p_param_list->p_ipuc_param = mem_malloc2(MEM_IPUC_MODULE, sizeof(ctc_ipuc_param_t), ctc_ipuc_param_t);
    if (NULL == p_param_list->p_ipuc_param)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        return CTC_E_NO_MEMORY;
    }

    p_param_list->ad_index = p_ipuc_info->ad_index;
    _sys_usw_ipuc_info_to_param(lchip, p_param_list->p_ipuc_param, p_ipuc_info);

    p_param_list->p_next_param = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_ipuc_param_list_t), sys_ipuc_param_list_t);
    if (NULL == p_param_list->p_next_param)
    {
        mem_free(p_param_list->p_ipuc_param);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_param_list->p_next_param, 0, sizeof(sys_ipuc_param_list_t));

    trav_data->value1++;
    trav_data->data = p_param_list;
    trav_data->data1 = (void*)p_param_list->p_next_param;

    return CTC_E_NONE;
}

/**
 @brief function of lookup ip route information

 @param[in] pp_ipuc_info, information used for lookup ipuc entry
 @param[out] pp_ipuc_info, information of ipuc entry finded

 @return CTC_E_XXX
 */
int32
_sys_usw_ipuc_db_lookup(uint8 lchip,
                sys_ipuc_param_t* p_sys_param)
{
    uint8 ip_ver = p_sys_param->param.ip_ver;
    sys_ipuc_info_t ipuc_info = {0};
    uint8 addr_size = (p_sys_param->param.ip_ver == CTC_IP_VER_4) ? sizeof(ip_addr_t) : sizeof(ipv6_addr_t);

    sal_memcpy(&(ipuc_info.ip), &(p_sys_param->param.ip), addr_size);
    ipuc_info.masklen = p_sys_param->param.masklen;
    ipuc_info.l4_dst_port = p_sys_param->param.l4_dst_port;

    if (CTC_FLAG_ISSET(p_sys_param->param.route_flag, CTC_IPUC_FLAG_PUBLIC_ROUTE))
    {
        ipuc_info.vrf_id = 0;
    }
    else
    {
        ipuc_info.vrf_id = p_sys_param->param.vrf_id;
    }
    if (p_sys_param->param.l4_dst_port)
    {
        CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_NAPT);
        if (p_sys_param->param.is_tcp_port)
        {
            CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_IS_TCP_PORT);
        }
    }
    if (CTC_FLAG_ISSET(p_sys_param->param.route_flag, CTC_IPUC_FLAG_PUBLIC_ROUTE))
    {
        CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE);
    }
    if (CTC_FLAG_ISSET(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM))
    {
        CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_HOST_USE_LPM);
    }

    p_sys_param->info = ctc_hash_lookup(p_usw_ipuc_master[lchip]->fib_hash[ip_ver], &ipuc_info);

    return CTC_E_NONE;
}

/**
 @brief function of add ip route information

 @param[in] p_ipuc_info, information should be maintained for ipuc

 @return CTC_E_XXX
 */
int32
_sys_usw_ipuc_db_add(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    ctc_hash_insert(p_usw_ipuc_master[lchip]->fib_hash[p_sys_param->param.ip_ver], p_sys_param->info);

    return CTC_E_NONE;
}

/**
 @brief function of add ip route information

 @param[in] p_ipuc_info, information should be maintained for ipuc

 @return CTC_E_XXX
 */
int32
_sys_usw_ipuc_db_remove(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    ctc_hash_remove(p_usw_ipuc_master[lchip]->fib_hash[p_sys_param->param.ip_ver], p_sys_param->info);

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_db_traverse(uint8 lchip,
                uint8 ip_ver,
                hash_traversal_fn   fn,
                void                *data)
{
    return ctc_hash_traverse_through(p_usw_ipuc_master[lchip]->fib_hash[ip_ver], fn, data);
}

#define __3_IPDA__

int32
_sys_usw_ipuc_read_ipda(uint8 lchip, uint16 ad_index, void* dsipda)
{
    uint32 cmd = 0;
    cmd = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), dsipda);
    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_add_ad_profile(uint8 lchip, sys_ipuc_param_t* p_sys_param, void* ad_profile, uint8 update)
{
    #ifdef IPUC_TEST_STUB
        //uint32 ad_index = p_sys_param->info->ad_index;
        uint32 ad_index = 0;
        CTC_ERROR_RETURN(sys_usw_ftm_alloc_table_offset(lchip, DsIpDa_t, 0, 1, 1, &ad_index));
        p_sys_param->info->ad_index = ad_index & 0x3fffd; /* for 0x3fff and 0x3fffe is invalid in chip*/
    #else

    sys_ipuc_ad_spool_t ipuc_ad_new;
    sys_ipuc_ad_spool_t ipuc_ad_old;
    sys_ipuc_ad_spool_t* p_ipuc_ad_get = NULL;
    DsIpDa_m   old_dsipda;

    CTC_PTR_VALID_CHECK(ad_profile);
    sal_memset(&ipuc_ad_new, 0, sizeof(ipuc_ad_new));
    sal_memset(&ipuc_ad_old, 0, sizeof(ipuc_ad_old));

    ipuc_ad_new.param.p_ad = ad_profile;
    ipuc_ad_new.param.ldp = p_sys_param->ldp;
    ipuc_ad_new.param.overlay_nh = p_sys_param->overlay_nhid;
    ipuc_ad_new.param.lchip = lchip;
    /*This update is only used when bind nexthop update to DsIpDa,
      the routing updates are based on the logic of adding and then deleting*/
    if (update)
    {
        uint32 cmd;

        cmd = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_sys_param->info->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &old_dsipda);
        ipuc_ad_old.param.p_ad = &old_dsipda;
        ipuc_ad_old.ad_index = p_sys_param->info->ad_index;
        ipuc_ad_old.param.lchip = lchip;
    }

    CTC_ERROR_RETURN(ctc_spool_add2(p_usw_ipuc_master[lchip]->ad_spool, &ipuc_ad_new, update ? &ipuc_ad_old:NULL, &p_ipuc_ad_get));
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC: alloc ad_index = %d\n", p_ipuc_ad_get->ad_index);

    p_sys_param->info->ad_index = p_ipuc_ad_get->ad_index;
    p_sys_param->dsipda_built = ipuc_ad_new.param.dsipda_built;
    #endif

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_remove_ad_profile(uint8 lchip, sys_ipuc_info_t* p_ipuc_info )
{
    #ifdef IPUC_TEST_STUB
        uint32 ad_index = p_ipuc_info->ad_index;
        CTC_ERROR_RETURN(sys_usw_ftm_free_table_offset(lchip, DsIpDa_t, 0, 1, ad_index));
    #else
    sys_ipuc_ad_spool_t ipuc_ad;
    uint32 cmd = 0;
    DsIpDa_m dsipda;

    cmd = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);
    ipuc_ad.param.p_ad = &dsipda;
    ipuc_ad.param.lchip = lchip;
    CTC_ERROR_RETURN(ctc_spool_remove2(p_usw_ipuc_master[lchip]->ad_spool, &ipuc_ad, NULL));
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC: remove ad_index = %d\n", p_ipuc_info->ad_index);
    #endif

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_ipuc_add_rpf(uint8 lchip, sys_ipuc_param_t* p_sys_param, sys_nh_info_dsnh_t* p_nhinfo)
{
    ctc_ipuc_param_t* p_ctc_param = &p_sys_param->param;
    sys_ipuc_info_t* p_ipuc_info = p_sys_param->info;
    sys_rpf_info_t rpf_info = {0};
    sys_nh_info_dsnh_t nh_info_1 = {0};
    uint32 idx = 0;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (p_ctc_param->masklen == 0 && DRV_IS_DUET2(lchip))
    {
        rpf_info.rpf_intf_cnt = 0;

        CTC_ERROR_RETURN(sys_usw_rpf_add_profile(lchip, &rpf_info));
        p_ipuc_info->rpf_mode = rpf_info.mode;
        p_ipuc_info->rpf_id =  rpf_info.rpf_id;

        return CTC_E_NONE;
    }

    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_CONNECT))
    {
        if ((p_ctc_param->l3_inf == SYS_L3IF_INVALID_L3IF_ID)
            || ((p_ctc_param->l3_inf > (MCHIP_CAP(SYS_CAP_SPEC_L3IF_NUM)-1)) && p_ctc_param->l3_inf != 0xffff))
        {
            return CTC_E_BADID;
        }
    }


    MALLOC_ZERO(MEM_IPUC_MODULE, p_nhinfo->nh_array, CTC_MAX_ECPN*sizeof(uint32));
    CTC_UNSET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NH_RPF_EN);
    CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo(lchip, p_ctc_param->nh_id, p_nhinfo, 0),ret,End);

    if(CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK)
         && p_nhinfo->ecmp_valid && p_nhinfo->rpf_profile_id)
    {
        p_ipuc_info->rpf_mode = SYS_RPF_CHK_MODE_PROFILE;
        p_ipuc_info->rpf_id = p_nhinfo->rpf_profile_id;
        CTC_SET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NH_RPF_EN);
        goto End;
    }

    if(CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK)
         && (p_ctc_param->l3_inf == 0xffff))
    {
       p_ipuc_info->rpf_mode = SYS_RPF_CHK_MODE_PROFILE;
       p_ipuc_info->rpf_id = 0;
       goto End;
    }

    if ((p_nhinfo->ecmp_valid) &&
        CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK))
    {
        rpf_info.rpf_intf_cnt = (p_nhinfo->ecmp_cnt > SYS_USW_MAX_RPF_IF_NUM) ? SYS_USW_MAX_RPF_IF_NUM : p_nhinfo->ecmp_cnt;
        for (idx = 0; idx < rpf_info.rpf_intf_cnt; idx++)
        {
            if (!p_usw_ipuc_master[lchip]->rpf_check_port)
            {
                CTC_ERROR_GOTO(sys_usw_nh_get_l3ifid(lchip, p_nhinfo->nh_array[idx], &rpf_info.rpf_intf[idx]),ret,End);
                if (rpf_info.rpf_intf[idx] == SYS_L3IF_INVALID_L3IF_ID)
                {
                    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop type is invalid \n");
                    ret = CTC_E_INVALID_CONFIG;
                    goto End;
                }
            }
            else
            {
                CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo(lchip, p_nhinfo->nh_array[idx], &nh_info_1, 0),ret,End);
                rpf_info.rpf_intf[idx] = nh_info_1.gport;
            }
        }
    }
    else if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK)
                && p_usw_ipuc_master[lchip]->rpf_check_port
                && p_ctc_param->rpf_port_num > 1)
    {
        rpf_info.rpf_intf_cnt = p_ctc_param->rpf_port_num;
        for (idx = 0; idx < p_ctc_param->rpf_port_num; idx++)
        {
            rpf_info.rpf_intf[idx] = p_ctc_param->rpf_port[idx];
        }
    }
    else
    {
        uint8 nh_is_unrov = 0;
        rpf_info.rpf_intf_cnt = 1;
        CTC_ERROR_GOTO(sys_usw_nh_is_unrov(lchip, p_ctc_param->nh_id, &nh_is_unrov),ret,End);

        if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_ICMP_CHECK)
            || CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK))
        {
            /* icmp check must use interfaceId*/
            if ((!p_usw_ipuc_master[lchip]->rpf_check_port)
                || CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_ICMP_CHECK))
            {
                if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_ASSIGN_PORT))
                {
                    rpf_info.rpf_intf[0] = p_ctc_param->rpf_port[0];
                }
                else if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_CONNECT))
                {
                    rpf_info.rpf_intf[0] = p_ctc_param->l3_inf;
                }
                else
                {
                    uint8 l3if_valid = 0;
                    ret = sys_usw_nh_get_l3ifid(lchip, p_ctc_param->nh_id, &rpf_info.rpf_intf[0]);
                    l3if_valid = !ret && (rpf_info.rpf_intf[0] != SYS_L3IF_INVALID_L3IF_ID) && nh_is_unrov;
                    if((p_nhinfo->drop_pkt && !l3if_valid) || p_nhinfo->to_cpu_en || CTC_IS_CPU_PORT(p_nhinfo->gport) ||
                       (!(CTC_IS_LINKAGG_PORT(p_nhinfo->gport)) &&
                         ((SYS_RSV_PORT_DROP_ID == CTC_MAP_GPORT_TO_LPORT(p_nhinfo->gport)) ||
                          (SYS_RSV_PORT_SPINE_LEAF_PORT == CTC_MAP_GPORT_TO_LPORT(p_nhinfo->gport)))))
                    {
                        rpf_info.rpf_intf[0] = 0xFFFF;
                    }
                    else if (rpf_info.rpf_intf[0] == SYS_L3IF_INVALID_L3IF_ID)
                    {
                        p_ipuc_info->rpf_mode = SYS_RPF_CHK_MODE_PROFILE;
                        p_ipuc_info->rpf_id = 0;
                        ret = CTC_E_NONE;
                        goto End;
                    }
                }
            }
            else
            {
                if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_ASSIGN_PORT)
                    && (p_ctc_param->rpf_port_num == 0))
                {
                       ret =  CTC_E_INVALID_PARAM;
                       goto End;
                }

                if (p_ctc_param->rpf_port_num > 0)
                {
                    rpf_info.rpf_intf[0] = p_ctc_param->rpf_port[0];
                }
                else
                {
                    if (p_nhinfo->drop_pkt || p_nhinfo->to_cpu_en || CTC_IS_CPU_PORT(p_nhinfo->gport) ||
                        (SYS_RSV_PORT_SPINE_LEAF_PORT == CTC_MAP_GPORT_TO_LPORT(p_nhinfo->gport)))
                    {
                        rpf_info.rpf_intf[0] = SYS_RSV_PORT_DROP_ID;
                    }
                    else
                    {
                        rpf_info.rpf_intf[0] = p_nhinfo->gport;
                    }

                }
            }
        }
    }

    CTC_ERROR_GOTO(sys_usw_rpf_add_profile(lchip, &rpf_info),ret,End);
    if(p_usw_ipuc_master[lchip]->slave_lchip_cnt > 1 && rpf_info.mode == SYS_RPF_CHK_MODE_PROFILE)
    {
        ret = CTC_E_NOT_SUPPORT;
    }

    p_ipuc_info->rpf_mode = rpf_info.mode;
    p_ipuc_info->rpf_id = rpf_info.rpf_id;
 End:
    mem_free(p_nhinfo->nh_array);
    return ret;
}

STATIC int32
_sys_usw_ipuc_build_ipda_nexthop(uint8 lchip, sys_ipuc_param_t* p_sys_param, sys_nh_info_dsnh_t* p_dsnh_info, DsIpDa_m* p_dsipda)
{
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (MCHIP_IPUC(lchip)->build_ipda_nexthop)
    {
        CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->build_ipda_nexthop(lchip, p_sys_param, p_dsnh_info, p_dsipda));
    }
    else
    {
        return CTC_E_INVALID_PTR;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_bind_nexthop(uint8 lchip, sys_ipuc_param_t* p_sys_param, uint8 is_bind)
{
    sys_nh_update_dsnh_param_t update_dsnh;
    uint32 nh_id = 0;
    int32 ret = 0;
    uint32 hash_idx = 0;
    ctc_hash_t* p_hash = NULL;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&update_dsnh, 0, sizeof(sys_nh_update_dsnh_param_t));
    p_hash = p_usw_ipuc_master[lchip]->fib_hash[p_sys_param->param.ip_ver];
    hash_idx = (p_sys_param->param.ip_ver == CTC_IP_VER_6) ? 0x80000000 :0;
    hash_idx |= p_hash->hash_key(p_sys_param->info)%(p_hash->block_size * p_hash->block_num);

    nh_id = (p_sys_param->info && p_sys_param->info->nh_id) ? p_sys_param->info->nh_id : p_sys_param->param.nh_id;
    /* host route, write dsnh to ipda */
    update_dsnh.data = is_bind ? p_sys_param->info : NULL;
    update_dsnh.updateAd = is_bind ? sys_usw_ipuc_update_ipda : NULL;
    update_dsnh.chk_data = is_bind ? hash_idx : 0;
    update_dsnh.bind_feature = is_bind ? CTC_FEATURE_IPUC : 0;
    DO_SLAVE_LOOP_START
    CTC_ERROR_GOTO(sys_usw_nh_bind_dsfwd_cb(lchip + (loop_lchip * SYS_PP_NUM(lchip)), nh_id, &update_dsnh), ret, error0);/* loop lchip binding,any chip bind fail,use dsfwd and do rollback */
    DO_SLAVE_LOOP_END

    if (is_bind)
    {
        CTC_SET_FLAG(p_sys_param->info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH);
    }
    else
    {
        CTC_UNSET_FLAG(p_sys_param->info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH);
    }

    return ret;
error0:
    if(is_bind && loop_lchip !=0 && loop_lchip != p_usw_ipuc_master[lchip]->slave_lchip_cnt)
    {
        update_dsnh.data = NULL;
        update_dsnh.updateAd = NULL;
        update_dsnh.chk_data = 0;
        update_dsnh.bind_feature = 0;
        do
        {
            loop_lchip--;
            sys_usw_nh_bind_dsfwd_cb(lchip + (loop_lchip * SYS_PP_NUM(lchip)), nh_id, &update_dsnh);
        } while (loop_lchip > 0);
    }

    return ret;
}

int32
_sys_usw_ipuc_build_ipda(uint8 lchip, sys_ipuc_param_t* p_sys_param, sys_nh_info_dsnh_t* p_nhinfo)
{
    sys_ipuc_info_t* p_ipuc_info = p_sys_param->info;
    int32 ret = CTC_E_NONE;
    uint32 stats_ptr = 0;
    uint8 have_dsfwd = 0;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_STATS_EN))
    {   /* check stats_id exist*/
        DO_SLAVE_LOOP_START
        CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param->param.stats_id, &stats_ptr));
        DO_SLAVE_LOOP_END
    }
    have_dsfwd = ((p_nhinfo->dsfwd_valid ||(p_nhinfo->merge_dsfwd == 2) || p_nhinfo->ecmp_valid || p_nhinfo->is_ivi ||
        CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_STATS_EN) || p_sys_param->param.fid) &&
        !CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_ASSIGN_PORT) && !p_nhinfo->is_ecmp_intf && (p_nhinfo->nh_entry_type != SYS_NH_TYPE_SRV6) &&
        ((p_nhinfo->nh_entry_type != SYS_NH_TYPE_OVERLAY)|| DRV_FROM_AT(lchip)));

    if (!have_dsfwd && !CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_ASSIGN_PORT) &&
        (p_nhinfo->merge_dsfwd != 1) && !SYS_USW_GET_DERIVE_MODE && (p_nhinfo->nh_entry_type != SYS_NH_TYPE_OVERLAY)
        && (p_nhinfo->nh_entry_type != SYS_NH_TYPE_SRV6))
    {
        /*do not using dsfwd, do nexthop and ipuc bind*/
        /*AT only first pp can bind nexthop, when more than one pp; and nexthop must use dsfwd if one or more fwd table bind nexthop*/
        ret = _sys_usw_ipuc_bind_nexthop(lchip, p_sys_param, 1);
        if (CTC_E_IN_USE == ret)
        {
            /*nh have already bind, do unbind, using dsfwd*/
            CTC_UNSET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH);
            have_dsfwd = 1;
        }
        else if (ret < 0)
        {
            /*Bind fail, using dsfwd*/
            have_dsfwd = 1;
        }
    }
    if (DRV_FROM_AT(lchip) && p_ipuc_info->nh_id == 1 && CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_SELF_ADDRESS))
    {
        have_dsfwd = 0;
    }
    
    if (!have_dsfwd || (p_nhinfo->merge_dsfwd == 1))
    {
        CTC_SET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_MERGE_KEY);
    }
    else
    {
        CTC_UNSET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_MERGE_KEY);
    }

    /* add rpf */
    if (CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_RPF_CHECK) || CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_ICMP_CHECK))
    {
        CTC_ERROR_GOTO(_sys_usw_ipuc_add_rpf(lchip, p_sys_param, p_nhinfo), ret, error0);
    }

    return CTC_E_NONE;

error0:
    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH))
    {
        _sys_usw_ipuc_bind_nexthop(lchip, p_sys_param, 0);
    }

    return ret;
}

int32
_sys_usw_ipuc_unbuild_ipda(uint8 lchip, sys_ipuc_param_t* p_sys_param, uint8 free_index)
{
    sys_ipuc_info_t* p_ipuc_info = p_sys_param->info;
    sys_rpf_info_t rpf_info = {0};
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* update nexthop info, remove nh bind */
    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH))
    {
        DO_SLAVE_LOOP_START
        CTC_ERROR_DUMP(_sys_usw_ipuc_bind_nexthop(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param, 0));
        DO_SLAVE_LOOP_END
    }

    /* remove rpf */
    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK) && !CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NH_RPF_EN))
    {
        rpf_info.mode = p_ipuc_info->rpf_mode;
        rpf_info.rpf_id = p_ipuc_info->rpf_id;
        CTC_ERROR_RETURN(sys_usw_rpf_remove_profile(lchip, &rpf_info));
    }
    if (free_index)
    {
        /* free ad profile */
        _sys_usw_ipuc_remove_ad_profile(lchip, p_ipuc_info);
    }

    return CTC_E_NONE;
}

#define __4_SHOW__

STATIC int32
_sys_usw_ipuc_traverse_pre(void* entry, void* p_trav)
{
    uint8 addr_len = 0;
    ctc_ipuc_param_t ipuc_param;
    ctc_ipuc_param_t* p_ipuc_param = &ipuc_param;
    sys_ipuc_info_t* p_ipuc_info = entry;
    hash_traversal_fn fn = ((sys_ipuc_traverse_t*)p_trav)->fn;
    void* data = ((sys_ipuc_traverse_t*)p_trav)->data;

    sal_memset(p_ipuc_param, 0, sizeof(ctc_ipuc_param_t));

    p_ipuc_param->nh_id = p_ipuc_info->nh_id;
    p_ipuc_param->vrf_id = p_ipuc_info->vrf_id;
    p_ipuc_param->route_flag = 0;
    SYS_IPUC_SYS2CTC_FLAG_CONVERT(p_ipuc_param->route_flag, p_ipuc_info->route_flag);
    p_ipuc_param->masklen = p_ipuc_info->masklen;
    p_ipuc_param->l4_dst_port = CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NAPT) ? p_ipuc_info->l4_dst_port:0;
    p_ipuc_param->is_tcp_port = CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_TCP_PORT)
        ? 1 : 0;
    p_ipuc_param->ip_ver = SYS_IPUC_VER(p_ipuc_info);

    if(DRV_IS_AT(((sys_ipuc_traverse_t*)p_trav)->lchip))
    {
        CTC_BIT_SET(p_ipuc_param->pp_bmp,((sys_ipuc_traverse_t*)p_trav)->lchip);
    }

    addr_len = (p_ipuc_param->ip_ver == CTC_IP_VER_4) ? sizeof(ip_addr_t): sizeof(ipv6_addr_t);
    sal_memcpy(&(p_ipuc_param->ip), &(p_ipuc_info->ip), addr_len);

    return (* fn)(p_ipuc_param, data);
}


int32
_sys_usw_ipuc_retrieve_ip(uint8 lchip, sys_ipuc_info_t *p_sys_ipuc_info)
{
    sys_ipuc_tcam_data_t tcam_data = {0};
    sys_ipuc_tbl_type_t tbl_type = SYS_TBL_HASH;
    sys_ipuc_info_t sys_ipuc_info_lookup = {0};
    sys_ipuc_param_t sys_ipuc_param_lookup = {0};
    uint32 tbl_id = 0;

    SYS_IPUC_INIT_CHECK;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\nDetail Table offset\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------\n");

    if (p_sys_ipuc_info->route_opt == DO_HASH)
    {
        tbl_type = CTC_FLAG_ISSET(p_sys_ipuc_info->route_flag, SYS_IPUC_FLAG_NAPT) ? SYS_TBL_HASH_NAPT : SYS_TBL_HASH;
        sys_usw_get_tbl_id(lchip, SYS_IPUC_VER(p_sys_ipuc_info), 1, tbl_type, &tbl_id, NULL);

        _sys_usw_ipuc_info_to_param(lchip, &sys_ipuc_param_lookup.param, p_sys_ipuc_info);
        sal_memcpy(&sys_ipuc_info_lookup, p_sys_ipuc_info, IPUC_INFO_SIZE(SYS_IPUC_VER(p_sys_ipuc_info)));
        sys_ipuc_param_lookup.info = &sys_ipuc_info_lookup;
        CTC_ERROR_RETURN(_sys_usw_ipuc_process_hash_key(lchip, &sys_ipuc_param_lookup, DO_LOOKUP));
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-25s:%d\n", DRV_TABLE_NAME(lchip, tbl_id), sys_ipuc_info_lookup.key_index);
    }
    else if (p_sys_ipuc_info->route_opt == DO_TCAM)
    {
        if (MCHIP_IPUC(lchip)->show_tcam_key)
        {
            tcam_data.key_type = SYS_IPUC_TCAM_FLAG_TCAM;
            tcam_data.key_index = p_sys_ipuc_info->key_index;
            tcam_data.info = (void*)p_sys_ipuc_info;

            MCHIP_IPUC(lchip)->show_tcam_key(lchip, &tcam_data);
        }
    }
    else if (p_sys_ipuc_info->route_opt == DO_ALPM)
    {
        _sys_usw_ipuc_info_to_param(lchip, &sys_ipuc_param_lookup.param, p_sys_ipuc_info);
        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_show_route_info)
        {
            MCHIP_IPUC(lchip)->nalpm2_show_route_info(lchip, &sys_ipuc_param_lookup.param);
        }
        else if (MCHIP_IPUC(lchip)->alpm_show_alpm_key)
        {
            MCHIP_IPUC(lchip)->alpm_show_alpm_key(lchip, &sys_ipuc_param_lookup.param);
        }
    }

    /* ad table */
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-25s:%d\n","DsIpDa", p_sys_ipuc_info->ad_index);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "----------------------------------\n");

    return CTC_E_NONE;
}

int32
_sys_usw_show_ipuc_info(sys_ipuc_info_t* p_ipuc_data, void* data)
{
    uint32 detail = 0;
    uint8   lchip = 0;
    uint32  route_flag = 0;
    char buf[CTC_IPV6_ADDR_STR_LEN];
    char buf2[20] = {0};
    char buf3[SYS_IPUC_L4PORT_LEN] = {0};
    char buf_s[2] = {0};
	char buf4[SYS_IPUC_MASK_LEN] = {0};

    detail = *((uint32*)(((sys_ipuc_traverse_t*)data)->data));
    lchip  = ((sys_ipuc_traverse_t*)data)->lchip;

    SYS_IPUC_INIT_CHECK;

    sal_sprintf(buf4, "/%d", p_ipuc_data->masklen);
    if (p_ipuc_data->l4_dst_port && CTC_FLAG_ISSET(p_ipuc_data->route_flag, SYS_IPUC_FLAG_NAPT))
    {
        sal_sprintf(buf3, "/%d", p_ipuc_data->l4_dst_port);
    }

    if (CTC_FLAG_ISSET(p_ipuc_data->route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-5s", "*");
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-5d", p_ipuc_data->vrf_id);
    }

    if (SYS_IPUC_VER(p_ipuc_data) == CTC_IP_VER_4)
    {
        uint32 tempip = sal_ntohl(p_ipuc_data->ip.ipv4);
        char buf[CTC_IPV6_ADDR_STR_LEN];

        sal_inet_ntop(AF_INET, &tempip, buf, CTC_IPV6_ADDR_STR_LEN);
        sal_strncat(buf, buf4, SYS_IPUC_MASK_LEN);
        sal_strncat(buf, buf3, SYS_IPUC_L4PORT_LEN);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-28s", buf);
    }
    else
    {
        uint32 ipv6_address[4] = {0, 0, 0, 0};

        ipv6_address[0] = sal_ntohl(p_ipuc_data->ip.ipv6[3]);
        ipv6_address[1] = sal_ntohl(p_ipuc_data->ip.ipv6[2]);
        ipv6_address[2] = sal_ntohl(p_ipuc_data->ip.ipv6[1]);
        ipv6_address[3] = sal_ntohl(p_ipuc_data->ip.ipv6[0]);

        sal_inet_ntop(AF_INET6, ipv6_address, buf, CTC_IPV6_ADDR_STR_LEN);
        sal_strncat(buf, buf4, SYS_IPUC_MASK_LEN);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-44s", buf);
    }

    buf2[0] = '\0';
    route_flag = p_ipuc_data->route_flag;
    CTC_UNSET_FLAG(route_flag, SYS_IPUC_FLAG_MERGE_KEY);
    CTC_UNSET_FLAG(route_flag, SYS_IPUC_FLAG_IS_IPV6);
    CTC_UNSET_FLAG(route_flag, SYS_IPUC_FLAG_DEFAULT);

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_RPF_CHECK))
    {
        buf_s[0] = 'R';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_TTL_CHECK))
    {
        buf_s[0] = 'T';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_CHECK))
    {
        buf_s[0] = 'I';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_ERR_MSG_CHECK))
    {
        buf_s[0] = 'E';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CPU))
    {
        buf_s[0] = 'C';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_PROTOCOL_ENTRY))
    {
        buf_s[0] = 'P';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_SELF_ADDRESS))
    {
        buf_s[0] = 'S';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_IS_TCP_PORT))
    {
        buf_s[0] = 'U';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(p_ipuc_data->route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE))
    {
        buf_s[0] = 'B';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(p_ipuc_data->route_flag, SYS_IPUC_FLAG_MERGE_KEY))
    {
        buf_s[0] = 'M';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(p_ipuc_data->route_flag, SYS_IPUC_FLAG_HOST_USE_LPM))
    {
        buf_s[0] = 'L';
        sal_strcat(buf2, buf_s);
    }

    if (CTC_FLAG_ISSET(p_ipuc_data->route_flag, SYS_IPUC_FLAG_CONNECT))
    {
        buf_s[0] = 'X';
        sal_strcat(buf2, buf_s);
    }

    if ('\0' == buf2[0])
    {
        buf_s[0] = 'O';
        sal_strcat(buf2, buf_s);
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-4u   %-5s   %-7s\n",
                      p_ipuc_data->nh_id, buf2,
                      (p_ipuc_data->route_opt != DO_HASH) ? "FALSE":"TRUE");

    if (detail)
    {
        _sys_usw_ipuc_retrieve_ip(lchip, p_ipuc_data);
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_db_show(uint8 lchip,
                ctc_ip_ver_t            ip_ver,
                sys_ipuc_info_t         *p_ipuc_data,
                uint32                  detail)
{
    sys_ipuc_traverse_t travs;

    LCHIP_CHECK(lchip);
	SYS_IPUC_INIT_CHECK;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Offset: T-TCAM    S-SRAM\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Flags:  R-RPF check    T-TTL check    I-ICMP redirect check      C-Send to CPU\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "        X-Connect      P-Protocol entry           S-Self address     U-TCP port\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "        E-ICMP error msg check    B-Public route    M-Merge dsfwd      L-Host use Lpm\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "        O-None flag\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "---------------------------------------------------------------------------------------\n");
    if (ip_ver == CTC_IP_VER_4)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "VRF   Route                      NHID   Flags   In_SRAM\n");
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "VRF   Route                                      NHID   Flags   In_SRAM\n");
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "---------------------------------------------------------------------------------------\n");

    travs.data = &detail;
    travs.lchip = lchip;

    if(p_ipuc_data)
    {
        _sys_usw_show_ipuc_info(p_ipuc_data, (void*)&travs);
    }
    else
    {
        _sys_usw_ipuc_db_traverse(lchip, ip_ver,
                    (hash_traversal_fn)_sys_usw_show_ipuc_info, (void*)&travs);
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_ad_fprintf_traverse(void *node, sys_dump_db_traverse_param_t* user_data)
{
    uint32 cmd;
    DsIpDa_m dsipda;
    sal_file_t p_file = (sal_file_t)user_data->value0;
    sys_ipuc_ad_spool_t* ipuc_ad = NULL;
    uint32* ptr = NULL;
    uint8 i = 0;
    uint8 lchip = 0;
    uint8* mode = (uint8 *)user_data->value2;
    ipuc_ad = (sys_ipuc_ad_spool_t*)((ctc_spool_node_t*)node)->data;

    lchip = user_data->lchip;
    cmd = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, ipuc_ad->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)), &dsipda);
    ptr = (uint32 *)&(dsipda);
    if(*mode == 1)
    {
        SYS_DUMP_DB_LOG(p_file, "%-10u%-10u%-10u0x", *(uint32 *)user_data->value1, ((ctc_spool_node_t*)node)->ref_cnt, ipuc_ad->ad_index);
        for (i = 0; i <= 2; i++)
        {
            SYS_DUMP_DB_LOG(p_file, "%08x", *ptr);
            ptr++;
        }
        SYS_DUMP_DB_LOG(p_file, "\n");
        SYS_DUMP_DB_LOG(p_file, "%s\n", "-----------------------------------------------------------------------------------");
    }
    (*(uint32 *)user_data->value1)++;

    return CTC_E_NONE;
}

#define __5_OTHER__

int32
_sys_usw_ipuc_add_ending(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    uint8 ip_ver = CTC_IP_VER_4;

    if(CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_IS_IPV6))
    {
        ip_ver = CTC_IP_VER_6;
    }

    /* stats */
    if (IS_MAX_MASKLEN(ip_ver, p_sys_param->info->masklen) && !CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_HOST_USE_LPM))
    {
        if(!CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_NAPT))
        {
            sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_HOST, 0);
        }
    }
    else if(!CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE) &&
            !CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
        sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_LPM, 0);
    }

    /* 7. write to soft table */
    _sys_usw_ipuc_db_add(lchip, p_sys_param);

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_remove_ending(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    uint8 ip_ver = CTC_IP_VER_4;

    if(CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_IS_IPV6))
    {
        ip_ver = CTC_IP_VER_6;
    }

    CTC_ERROR_RETURN(_sys_usw_ipuc_db_remove(lchip, p_sys_param));
    CTC_ERROR_RETURN(_sys_usw_ipuc_unbuild_ipda(lchip, p_sys_param, !CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_DEFAULT)));
    /* stats */
    if (IS_MAX_MASKLEN(ip_ver, p_sys_param->info->masklen) && !CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_HOST_USE_LPM))
    {
        if(!CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_NAPT))
        {
            sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_HOST, 1);
        }
    }
    else if(!CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE) &&
            !CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
         sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_LPM, 1);
    }

    /*Default route AD mode,recover default route ad to drop*/
    if(p_usw_ipuc_master[lchip]->default_route_mode && CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
        _sys_usw_ipuc_add_default_entry(lchip, ip_ver, p_sys_param->param.vrf_id, SYS_NH_RESOLVED_NHID_FOR_DROP, 1);
    }
    SYS_WB_FREE(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO,p_sys_param->info);

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_update_ending(uint8 lchip, sys_ipuc_info_t* p_old_info)
{
    sys_rpf_info_t rpf_info = {0};

    if (CTC_FLAG_ISSET(p_old_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK) && !CTC_FLAG_ISSET(p_old_info->route_flag, SYS_IPUC_FLAG_NH_RPF_EN))
    {
        rpf_info.mode = p_old_info->rpf_mode;
        rpf_info.rpf_id = p_old_info->rpf_id;
        sys_usw_rpf_remove_profile(lchip, &rpf_info);
    }
    /* free old ad profile */
    if (!CTC_FLAG_ISSET(p_old_info->route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
        _sys_usw_ipuc_remove_ad_profile(lchip, p_old_info);
    }

    return CTC_E_NONE;
}

uint32
_sys_usw_ipuc_get_store_position(uint8 lchip, sys_ipuc_param_t* p_sys_param, uint8* opt)
{
    ctc_ipuc_param_t* p_ctc_param = &p_sys_param->param;
    uint8 ip_ver = p_ctc_param->ip_ver;
    uint8 masklen = p_ctc_param->masklen;
    uint32 host_in_hash_resource;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (p_ctc_param->l4_dst_port) /*NAPT use hash*/
    {
        if (!CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_HASH_NAPT_LOOKUP))
        {
            return CTC_E_NO_RESOURCE;
        }

        *opt = DO_HASH;
    }
    else if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_PUBLIC_ROUTE))
    {
        if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_TCAM_PUB_LOOKUP) ||
           CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_TCAM_PUB_SHORT_LOOKUP))
           {
               *opt = DO_TCAM;
           }
    }
    else if((IS_MAX_MASKLEN(ip_ver, masklen)
         && !p_sys_param->hash_conflict
         && !CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM)
         &&  CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_HASH_LOOKUP)))
    {   /*Host Route (32 or 128)*/
       *opt = DO_HASH;
        host_in_hash_resource = sys_usw_ftm_get_host_size_in_hash(lchip);
        if((p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HASH]+2*p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HASH]) >= host_in_hash_resource)
        {
            *opt = DO_TCAM;
            p_sys_param->hash_conflict = 1;
        }
    }
    else if((CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_TCAM_LOOKUP)
             ||CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_TCAM_SHORT_LOOKUP)))
    {
        *opt = DO_TCAM;

        if (DRV_IS_DUET2(lchip))
        {   /*CALPM*/
 #ifdef DUET2
            if (((masklen >= MIN_CALPM_MASKLEN(lchip, ip_ver)) && (masklen <= MAX_CALPM_MASKLEN(lchip, ip_ver))) &&
                !(IS_MAX_MASKLEN(ip_ver, masklen) && p_usw_ipuc_master[lchip]->host_lpm_mode) && !(CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_PUBLIC_ROUTE)) &&
            CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_ALPM_LOOKUP) && !IS_MAX_MASKLEN(ip_ver, masklen))
            {

                *opt = DO_ALPM;
            }
#endif
        }
        else
        {   /*NALPM*/
            if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_ALPM_LOOKUP))
            {
                if (0 == p_usw_ipuc_master[lchip]->prefix64_mode || 2 == p_usw_ipuc_master[lchip]->prefix64_mode)
                {
                    if ((p_usw_ipuc_master[lchip]->host_lpm_mode == 2)
                        || !(IS_MAX_MASKLEN(ip_ver, masklen))
                        || (p_usw_ipuc_master[lchip]->host_lpm_mode == 1
                    && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM)))
                    {
                        *opt = DO_ALPM;
                    }
                }
                else /* prefix64_mode 1/3 */
                {
                    if (ip_ver == CTC_IP_VER_6 &&  masklen <= 64 && !p_sys_param->hash_conflict)
                    {
                        *opt = DO_ALPM;
                    }
                    else if(ip_ver == CTC_IP_VER_4)
                    {
                        if ((p_usw_ipuc_master[lchip]->host_lpm_mode == 2)
                            || (p_usw_ipuc_master[lchip]->use_snake64 && p_usw_ipuc_master[lchip]->host_lpm_mode == 1)
                            || !(IS_MAX_MASKLEN(ip_ver, masklen)))
                        {
                            *opt = DO_ALPM;
                        }
                    }
                }
            }
        }
    }

    if (*opt == 0)
    {
        return CTC_E_NO_RESOURCE;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_process_hash_key(uint8 lchip, sys_ipuc_param_t* p_sys_param, sys_ipuc_opt_type_t opt)
{
    uint8 valid = 0;
    uint8 l4PortType = 0;
    uint8 loop_lchip = 0;
    ds_t key;
    ipv6_addr_t ipv6_data;
    drv_acc_in_t fib_acc_in;
    drv_acc_out_t fib_acc_out;
    sys_ipuc_tbl_type_t tbl_type;
    sys_ipuc_info_t* p_ipuc_info = p_sys_param->info;
    ctc_ipuc_param_t* p_ctc_param = &p_sys_param->param;
    int32 ret = CTC_E_NONE;

    sal_memset(&key, 0, sizeof(ds_t));
    sal_memset(&ipv6_data, 0, sizeof(ipv6_data));
    sal_memset(&fib_acc_in, 0, sizeof(fib_acc_in));
    sal_memset(&fib_acc_out, 0, sizeof(fib_acc_out));

    fib_acc_in.oper_bmp = DRV_ACC_BMP_EN(MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC));
    if (!p_sys_param->param.l4_dst_port)
    {
        valid = (opt == DO_DEL) ? 0 : 1;
        if (CTC_IP_VER_4 == p_sys_param->param.ip_ver)
        {
            SetDsFibHost0Ipv4HashKey(V, ipDa_f, &key, p_ctc_param->ip.ipv4);
            SetDsFibHost0Ipv4HashKey(V, vrfId_f, &key, p_ctc_param->vrf_id);
            SetDsFibHost0Ipv4HashKey(V, valid_f, &key, valid);
            SetDsFibHost0Ipv4HashKey(V, dsAdIndex_f, &key, p_ipuc_info->ad_index);
            SetDsFibHost0Ipv4HashKey(V, ipv4Type_f, &key, 0);
            SetDsFibHost0Ipv4HashKey(V, hashType_f, &key, DRV_ENUM(DRV_FIBHOST0PRIMARYHASHTYPE_IPV4));
        }
        else
        {
            /* DRV_SET_FIELD_A, ipv6_data must use little india */
            sal_memcpy(&ipv6_data, &(p_ctc_param->ip.ipv6), sizeof(ipv6_addr_t));
            SetDsFibHost0Ipv6UcastHashKey(A, ipDa_f, &key, ipv6_data);
            SetDsFibHost0Ipv6UcastHashKey(V, vrfId_f, &key, p_ctc_param->vrf_id);
            SetDsFibHost0Ipv6UcastHashKey(V, valid0_f, &key, valid);
            SetDsFibHost0Ipv6UcastHashKey(V, valid1_f, &key, valid);
            SetDsFibHost0Ipv6UcastHashKey(V, dsAdIndex_f, &key, p_ipuc_info->ad_index);
            SetDsFibHost0Ipv6UcastHashKey(V, hashType0_f, &key, DRV_ENUM(DRV_FIBHOST0PRIMARYHASHTYPE_IPV6UCAST));
            SetDsFibHost0Ipv6UcastHashKey(V, hashType1_f, &key, DRV_ENUM(DRV_FIBHOST0PRIMARYHASHTYPE_IPV6UCAST));
        }
        tbl_type = SYS_TBL_HASH;
        sys_usw_get_tbl_id(lchip, p_ctc_param->ip_ver, 1, tbl_type, &fib_acc_in.tbl_id, NULL);
        fib_acc_in.module= DRV_ACC_HASH_MODULE_FIB_HOST0;
        if(opt == DO_ADD)
        {
            fib_acc_in.type = DRV_ACC_TYPE_ADD;
            fib_acc_in.op_type = DRV_ACC_OP_BY_KEY;
            fib_acc_in.data = (void*)key;

            DO_SLAVE_LOOP_START
            CTC_ERROR_GOTO(drv_acc_api(lchip + (loop_lchip * SYS_PP_NUM(lchip)), &fib_acc_in, &fib_acc_out), ret, error0);
            if (fib_acc_out.is_conflict ||
            (fib_acc_out.key_index < 32 && !p_usw_ipuc_master[lchip]->arc[CTC_IP_VER_6] && p_ctc_param->ip_ver == CTC_IP_VER_4))
            {
                /* cam use for resolve ipv6 conflict, ipv4 can not use ,only when host-use-lpm mode 2 or no ipv6 tcam*/
                if(!fib_acc_out.is_conflict)
                {
                    loop_lchip++;
                }
                ret =  CTC_E_HASH_CONFLICT;
                goto error0;
            }
            DO_SLAVE_LOOP_END

            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC: %s %s key_index = 0x%x\n", (opt == DO_ADD) ? "write" : "remove", DRV_TABLE_NAME(lchip, fib_acc_in.tbl_id), p_ipuc_info->key_index);
            return CTC_E_NONE;
        }
        else
        {
            fib_acc_in.type = (opt == DO_LOOKUP) ? DRV_ACC_TYPE_LOOKUP : DRV_ACC_TYPE_ADD;
            if (opt != DO_LOOKUP)
            {
                CTC_BIT_SET(fib_acc_in.flag, DRV_ACC_OVERWRITE_EN);
            }
            fib_acc_in.op_type = DRV_ACC_OP_BY_KEY;
            fib_acc_in.data = (void*)key;
            //fib_acc_in.index = p_ipuc_info->key_index;
        }
    }
    else
    {
        SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IP_TUNNEL, SYS_WB_APPID_IP_TUNNEL_SUBID_MASTER, 1);
        valid = 1;
        l4PortType = (p_ipuc_info->route_flag & SYS_IPUC_FLAG_IS_TCP_PORT) ? 3 : 2;
        if(CTC_IP_VER_4 == p_sys_param->param.ip_ver)
        {
            SetDsFibHost1Ipv4NatDaPortHashKey(V, ipDa_f, &key, p_ctc_param->ip.ipv4);
            SetDsFibHost1Ipv4NatDaPortHashKey(V, l4DestPort_f, &key, p_ctc_param->l4_dst_port);
            SetDsFibHost1Ipv4NatDaPortHashKey(V, l4PortType_f, &key, l4PortType);
            SetDsFibHost1Ipv4NatDaPortHashKey(V, vrfId_f, &key, p_ctc_param->vrf_id);
            SetDsFibHost1Ipv4NatDaPortHashKey(V, valid_f, &key, valid);
            SetDsFibHost1Ipv4NatDaPortHashKey(V, dsAdIndex_f, &key, p_ipuc_info->ad_index);
            SetDsFibHost1Ipv4NatDaPortHashKey(V, ipv4Type_f, &key, 0);
            SetDsFibHost1Ipv4NatDaPortHashKey(V, hashType_f, &key, DRV_ENUM(DRV_FIBHOST1PRIMARYHASHTYPE_IPV4));
        }
        else
        {
            SetDsFibHost1Ipv6NatDaPortHashKey(V, hashType0_f, &key, DRV_ENUM(DRV_FIBHOST1PRIMARYHASHTYPE_IPV6NATDA));
            SetDsFibHost1Ipv6NatDaPortHashKey(V, hashType1_f, &key, DRV_ENUM(DRV_FIBHOST1PRIMARYHASHTYPE_IPV6NATDA));
            SetDsFibHost1Ipv6NatDaPortHashKey(V, l4PortType_f, &key, l4PortType);
            SetDsFibHost1Ipv6NatDaPortHashKey(V, dsAdIndex_f, &key, p_ipuc_info->ad_index);
            SetDsFibHost1Ipv6NatDaPortHashKey(V, l4DestPort_f, &key, p_ctc_param->l4_dst_port);
            SetDsFibHost1Ipv6NatDaPortHashKey(A, ipDa_f, &key, p_ctc_param->ip.ipv6);
            SetDsFibHost1Ipv6NatDaPortHashKey(V, valid0_f, &key, valid);
            SetDsFibHost1Ipv6NatDaPortHashKey(V, valid1_f, &key, valid);
        }

        tbl_type = SYS_TBL_HASH_NAPT;
        fib_acc_in.module= DRV_ACC_HASH_MODULE_FIB_HOST1;
        sys_usw_get_tbl_id(lchip, p_ctc_param->ip_ver, 1, tbl_type, &fib_acc_in.tbl_id, NULL);
        fib_acc_in.type = (opt == DO_LOOKUP) ? DRV_ACC_TYPE_LOOKUP : ((opt == DO_DEL)?DRV_ACC_TYPE_DEL : DRV_ACC_TYPE_LOOKUP);
        fib_acc_in.op_type = DRV_ACC_OP_BY_KEY;
        fib_acc_in.data = (void*)key;
        if (opt == DO_ADD || opt == DO_UPDATE)
        {
            CTC_ERROR_RETURN(drv_acc_api(lchip, &fib_acc_in, &fib_acc_out));
            if (fib_acc_out.is_conflict)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [IPUC] Hash confict \n");
                return CTC_E_HASH_CONFLICT;
            }
            fib_acc_in.type = DRV_ACC_TYPE_ADD;
        }
    }

    if(opt == DO_LOOKUP)
    {
        CTC_ERROR_RETURN(drv_acc_api(lchip, &fib_acc_in, &fib_acc_out));
    }
    else
    {  
        DO_SLAVE_LOOP_START
        CTC_ERROR_GOTO(drv_acc_api(lchip + (loop_lchip * SYS_PP_NUM(lchip)), &fib_acc_in, &fib_acc_out), ret , error0);
        if (fib_acc_out.is_conflict)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [IPUC] Hash confict \n");
            ret = CTC_E_HASH_CONFLICT;
            goto error0;
        }
        DO_SLAVE_LOOP_END
    }

    p_ipuc_info->key_index = fib_acc_out.key_index;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC: %s %s key_index = 0x%x\n", (opt == DO_ADD) ? "write" : "remove", DRV_TABLE_NAME(lchip, fib_acc_in.tbl_id), p_ipuc_info->key_index);

    return CTC_E_NONE;

error0:
    /* rollback for success chip */
    if(loop_lchip != 0 && opt != DO_DEL)
    {
        do
        {
            loop_lchip--;
            if(opt == DO_ADD)
            {
                if (CTC_IP_VER_4 == p_sys_param->param.ip_ver)
                {
                    SetDsFibHost0Ipv4HashKey(V, valid_f, &key, 0);
                }
                else
                {
                    SetDsFibHost0Ipv6UcastHashKey(V, valid0_f, &key, 0);
                    SetDsFibHost0Ipv6UcastHashKey(V, valid1_f, &key, 0);
                }
                fib_acc_in.type = DRV_ACC_TYPE_ADD;
                fib_acc_in.op_type = DRV_ACC_OP_BY_KEY;
            }
            else if(opt == DO_UPDATE)
            {
                if (CTC_IP_VER_4 == p_sys_param->param.ip_ver)
                {
                    SetDsFibHost0Ipv4HashKey(V, dsAdIndex_f, &key, p_sys_param->old_ad_index);
                }
                else
                {
                    SetDsFibHost0Ipv6UcastHashKey(V, dsAdIndex_f, &key, p_sys_param->old_ad_index);
                }
                CTC_BIT_SET(fib_acc_in.flag, DRV_ACC_OVERWRITE_EN);
                fib_acc_in.type = DRV_ACC_TYPE_ADD;
                fib_acc_in.op_type = DRV_ACC_OP_BY_KEY;
            }
            CTC_ERROR_DUMP(drv_acc_api(lchip + (loop_lchip * SYS_PP_NUM(lchip)), &fib_acc_in, &fib_acc_out));
        }while (loop_lchip > 0);
    }

    return ret;
}

STATIC int32
_sys_usw_ipuc_check(uint8 lchip, ctc_ipuc_param_t* p_ctc_param)
{
    CTC_PTR_VALID_CHECK(p_ctc_param);
    CTC_IP_VER_CHECK(p_ctc_param->ip_ver);
    CTC_MAX_VALUE_CHECK(p_ctc_param->route_data,0xF);
    SYS_IP_CHECK_VERSION_ENABLE(p_ctc_param->ip_ver);
    SYS_IP_VRFID_CHECK(p_ctc_param->vrf_id);
    SYS_IPUC_MASK_LEN_CHECK(p_ctc_param->ip_ver, p_ctc_param->masklen);
    if (p_ctc_param->ip_ver)
    {
        SYS_IPV6_ADDRESS_SORT(p_ctc_param->ip.ipv6);
    }
    SYS_IP_ADDR_MASK(p_ctc_param->ip, p_ctc_param->masklen, p_ctc_param->ip_ver);
    SYS_USW_CID_CHECK(lchip,p_ctc_param->cid);
    SYS_GLOBAL_PORT_CHECK(p_ctc_param->gport);
    if((1 == p_ctc_param->nh_id || 2 == p_ctc_param->nh_id) && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_ASSIGN_PORT))
    {
        return CTC_E_INVALID_PARAM;
    }
    if (0 == p_usw_ipuc_master[lchip]->max_size_of_snake && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM) && !DRV_IS_DUET2(lchip))
    {
        return CTC_E_INVALID_PARAM;
    }
    if ((SYS_GET_CHIP_VERSION == SYS_CHIP_SUB_VERSION_A) && DRV_IS_TSINGMA(lchip) && p_ctc_param->fid)
    {
        return CTC_E_NOT_SUPPORT;
    }
    if((CTC_FLAG_ISSET(p_ctc_param->route_flag, SYS_IPUC_FLAG_RPF_CHECK)) &&
       (p_ctc_param->l3_inf == 0xffff) &&
       (CTC_FLAG_ISSET(p_ctc_param->route_flag, SYS_IPUC_FLAG_ICMP_CHECK)))
    {
        return CTC_E_NOT_SUPPORT;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_ipuc_spec_check(uint8 lchip, ctc_ipuc_param_t* p_ctc_param)
{

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (IS_MAX_MASKLEN(p_ctc_param->ip_ver, p_ctc_param->masklen) &&
            !CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM) &&
            !p_ctc_param->l4_dst_port)
    {
        if (((CTC_IP_VER_4 == p_ctc_param->ip_ver) && (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HOST] >= SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_HOST)))
            || ((CTC_IP_VER_6 == p_ctc_param->ip_ver) && (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HOST] >= SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_ND))))
        {
            return CTC_E_NO_RESOURCE;
        }
    }
    else if (!IS_MAX_MASKLEN(p_ctc_param->ip_ver, p_ctc_param->masklen) ||
             (IS_MAX_MASKLEN(p_ctc_param->ip_ver, p_ctc_param->masklen) &&
              CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM)))
    {
        if ((CTC_IP_VER_4 == p_ctc_param->ip_ver) && (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_LPM] >= SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_LPM)))
        {
            return CTC_E_NO_RESOURCE;
        }
        else if ((CTC_IP_VER_6 == p_ctc_param->ip_ver) && (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_LPM] >= SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_LPMv6)))
        {
            return CTC_E_NO_RESOURCE;
        }
    }
    else if (IS_MAX_MASKLEN(p_ctc_param->ip_ver, p_ctc_param->masklen) && p_ctc_param->l4_dst_port)
    {
        if ((p_usw_ip_tunnel_master[lchip]->snat_hash_count +
             p_usw_ip_tunnel_master[lchip]->napt_hash_count) >=
            SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_NAPT))
        {
            return CTC_E_NO_RESOURCE;
        }
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_ipuc_flag_check(uint8 lchip, ctc_ipuc_param_t* p_ctc_param, uint8 check_nh, sys_nh_info_dsnh_t* p_nhinfo)
{
    sys_nh_info_dsnh_t nh_info;

    CTC_PTR_VALID_CHECK(p_ctc_param);
    sal_memset(&nh_info, 0, sizeof(sys_nh_info_dsnh_t));

    if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_TTL_CHECK) && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_TTL_NO_CHECK))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Config Conflict \n");
        return CTC_E_PARAM_CONFLICT;
    }
    if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_AGING_EN))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_PUBLIC_ROUTE) &&
        (!CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP)||
         (p_usw_ipuc_master[lchip]->default_route_mode && 0 == p_ctc_param->masklen)))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
        return CTC_E_NOT_SUPPORT;
    }

    /* host use lpm flag check */
    if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM))
    {
        if (!IS_MAX_MASKLEN(p_ctc_param->ip_ver, p_ctc_param->masklen) || CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_PUBLIC_ROUTE))
        /* clear host use lpm flag */
        CTC_UNSET_FLAG(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
    }

    if (check_nh && p_nhinfo)
    {
        /* icmp flag check */
        if ((p_nhinfo->ecmp_valid) && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_ICMP_CHECK))
        {
            /* clear icmp-check flag */
            CTC_UNSET_FLAG(p_ctc_param->route_flag, CTC_IPUC_FLAG_ICMP_CHECK);
        }

        if ((p_nhinfo->ecmp_valid)
            && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_RPF_CHECK)
            && p_nhinfo->ecmp_cnt > SYS_USW_MAX_RPF_IF_NUM)
        {
            return CTC_E_INVALID_PARAM;
        }

        /* assign port check */
        if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_ASSIGN_PORT)
            && p_nhinfo->ecmp_valid)
        {
            return CTC_E_INVALID_PARAM;
        }

        if (nh_info.nh_entry_type == SYS_NH_TYPE_OVERLAY)
        {
            if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_STATS_EN))
            {
                return CTC_E_INVALID_PARAM;
            }

            if (p_ctc_param->fid && p_ctc_param->cid)
            {
                return CTC_E_INVALID_PARAM;
            }
        }

    }


    if (p_usw_ipuc_master[lchip]->rpf_check_port)
    {
        if(CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_ICMP_CHECK) && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_RPF_CHECK))
        {
            /* when rpf check port, icmp check and rpf check can not both support */
            return CTC_E_INVALID_PARAM;
        }
        if(CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_ICMP_CHECK) && CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_ASSIGN_PORT))
        {
            /*when icmp check ,need check dest interface ,but not dest port*/
            return CTC_E_INVALID_PARAM;
        }
    }

    /* NAPT check */
    if (p_ctc_param->l4_dst_port > 0)
    {
        if (!IS_MAX_MASKLEN(p_ctc_param->ip_ver, p_ctc_param->masklen))
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [IPUC] NAPT not support this mask length. for IPV4 only support mask length 32 \n");
            return CTC_E_INVALID_CONFIG;
        }

        if(p_usw_ipuc_master[lchip]->slave_lchip_cnt > 1)
        {
            return CTC_E_NOT_SUPPORT;
        }

        if (p_ctc_param->ip_ver == CTC_IP_VER_6 &&
            (!DRV_FROM_AT(lchip) || p_ctc_param->vrf_id != 0))
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Feature not supported \n");
            return CTC_E_NOT_SUPPORT;
        }

        if (CTC_FLAG_ISSET(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM))
        {
            CTC_UNSET_FLAG(p_ctc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
        }
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_rpf_check_port(uint8 lchip, uint8 enable)
{
    uint32 cmd = 0;
    uint32 field_value = 0;

    SYS_IPUC_INIT_CHECK;
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_MASTER, 1);

    cmd = DRV_IOW(IpeRouteCtl_t, IpeRouteCtl_rpfCheckAgainstPort_f);
    field_value = enable ? 1 : 0;

    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));
    p_usw_ipuc_master[lchip]->rpf_check_port = enable?1:0;

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_host_pre_process(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    uint32 route_flag = p_sys_param->param.route_flag;
    uint8 ip_ver = p_sys_param->param.ip_ver;
    int32 ret = CTC_E_NONE;
    uint32 hash_key_index = 0;
    uint32 tcam_key_index = 0;
    

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (CTC_FLAG_ISSET(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM))
    {
        CTC_UNSET_FLAG(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
        ret = _sys_usw_ipuc_db_lookup(lchip, p_sys_param);
        if (ret || !p_sys_param->info)
        {
            CTC_SET_FLAG(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
            return ret;
        }

        if (p_sys_param->info->route_opt == DO_HASH)
        {
            uint8 hit = 0;
            uint8 domain_type = 0;

            /* get aging status*/
            domain_type =  CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_NAPT)?SYS_AGING_DOMAIN_HOST1:SYS_AGING_DOMAIN_IP_HASH;
            MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;
            CTC_ERROR_RETURN(sys_usw_aging_get_aging_status(lchip, domain_type, p_sys_param->info->key_index, &hit));

            /* add to tcam first */
            hash_key_index = p_sys_param->info->key_index;
            CTC_SET_FLAG(p_sys_param->info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT);
            ret = sys_usw_ipuc_add_tcam(lchip, p_sys_param);
            if (ret)
            {
                CTC_UNSET_FLAG(p_sys_param->info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT);
                CTC_SET_FLAG(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
                return ret;
            }
            tcam_key_index = p_sys_param->info->key_index;
            /* delete hash */
            p_sys_param->info->key_index = hash_key_index;
            ret = _sys_usw_ipuc_process_hash_key(lchip, p_sys_param, DO_DEL);
            if (ret)
            {
                p_sys_param->info->key_index = tcam_key_index;
                sys_usw_ipuc_del_tcam(lchip, p_sys_param);
                CTC_UNSET_FLAG(p_sys_param->info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT);
                CTC_SET_FLAG(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
                return ret;
            }
            /* clear old aging status*/
            CTC_ERROR_RETURN(sys_usw_aging_set_aging_status(lchip, domain_type, hash_key_index, 0, 0));
            
            p_sys_param->info->key_index = tcam_key_index;
            p_sys_param->info->route_opt = DO_TCAM;
            sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_HASH, 1);
            sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_CONFLICT_TCAM, 0);
            
            /* update aging status*/
            domain_type = SYS_AGING_DOMAIN_TCAM;
            MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;
            CTC_ERROR_RETURN(sys_usw_aging_set_aging_status(lchip, domain_type, p_sys_param->info->key_index, 0, hit));
        }
    }
    else
    {
        CTC_SET_FLAG(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
        CTC_ERROR_RETURN(_sys_usw_ipuc_db_lookup(lchip, p_sys_param));
        if (p_sys_param->info)
        {
            p_sys_param->hash_conflict = 1;
        }
    }
    p_sys_param->param.route_flag = route_flag;

    return CTC_E_NONE;
}


int32
_sys_usw_ipuc_add_default_entry(uint8 lchip, uint8 ip_ver, uint16 vrfid, uint32 nh_id, uint8 by_user)
{
    ctc_ipuc_param_t ctc_param = {0};
    sys_ipuc_param_t sys_param = {0};
    sys_ipuc_info_t  ipuc_info = {0};
    sys_nh_info_dsnh_t nhinfo = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&ctc_param, 0, sizeof(ctc_param));
    sal_memset(&sys_param, 0, sizeof(sys_param));
    sal_memset(&ipuc_info, 0, sizeof(ipuc_info));
    sal_memset(&nhinfo, 0, sizeof(nhinfo));

    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, nh_id, &nhinfo, 0));

    ctc_param.masklen = 0;
    ctc_param.nh_id = nh_id;
    ipuc_info.route_flag |= (ip_ver == CTC_IP_VER_6) ? SYS_IPUC_FLAG_IS_IPV6 : 0;

    ipuc_info.route_flag |= SYS_IPUC_FLAG_DEFAULT | SYS_IPUC_FLAG_RPF_CHECK;
    ipuc_info.ad_index = p_usw_ipuc_master[lchip]->default_base[ip_ver] + vrfid;
    ipuc_info.vrf_id = vrfid;

    sys_param.param = ctc_param;
    sys_param.info = &ipuc_info;

    CTC_ERROR_RETURN(_sys_usw_ipuc_add_rpf(lchip, &sys_param, &nhinfo));

    if (MCHIP_IPUC(lchip)->write_ipda)
    {
        CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->write_ipda(lchip, &sys_param, by_user, &nhinfo));
    }
    else
    {
        return  CTC_E_INVALID_PTR;
    }

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_ipuc_update(uint8 lchip,
                sys_ipuc_param_t *p_sys_param,
                sys_nh_info_dsnh_t* p_nhinfo)
{
    sys_ipuc_info_t* p_new_info = p_sys_param->info;
    sys_ipuc_info_t old_info = {0};
    int32 ret = CTC_E_NONE;
    uint8 old_bind_flag = 0;
    uint8 db_size = 0;
    sys_ipuc_param_t unbind_param;
    uint8 free_index = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&unbind_param, 0, sizeof(unbind_param));

     /* save old rpf info and ad index */
    db_size = IPUC_INFO_SIZE(p_sys_param->param.ip_ver);
    sal_memcpy(&old_info, p_new_info, db_size);

    /* 1. remove old ad resource */
    old_bind_flag = CTC_FLAG_ISSET(old_info.route_flag, SYS_IPUC_FLAG_IS_BIND_NH) ? 1 : 0;

    unbind_param.info = p_sys_param->info;

    if (old_bind_flag )
    {
        _sys_usw_ipuc_bind_nexthop(lchip, &unbind_param, 0);
    }

    _sys_usw_ipuc_param_to_info(lchip, &p_sys_param->param, p_new_info);

    /* 2. build and write ipda, include ad profile */
    CTC_ERROR_GOTO(_sys_usw_ipuc_build_ipda(lchip, p_sys_param, p_nhinfo), ret, error0);

    if (MCHIP_IPUC(lchip)->write_ipda)
    {
        CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->write_ipda(lchip, p_sys_param , 1, p_nhinfo), ret, error1);
    }
    else
    {
        ret = CTC_E_INVALID_PTR;
        goto error1;
    }

    free_index = 1;

    /* 3. write key */
    if(p_new_info->ad_index != old_info.ad_index)
    {
        p_sys_param->old_ad_index = old_info.ad_index;
        if (p_new_info->route_opt == DO_HASH)
        {
            CTC_ERROR_GOTO(_sys_usw_ipuc_process_hash_key(lchip, p_sys_param, DO_UPDATE), ret, error1);
        }
        else
        {
            if (p_new_info->route_opt == DO_ALPM)
            {
                if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_update)
                {
                    ret = MCHIP_IPUC(lchip)->nalpm2_update(lchip, p_sys_param, p_sys_param->info->ad_index);
                }
                else if (MCHIP_IPUC(lchip)->alpm_update)
                {
                    ret = MCHIP_IPUC(lchip)->alpm_update(lchip, p_sys_param, p_sys_param->info->ad_index);
                }
            }
            else
            {
                ret = sys_usw_ipuc_update_tcam(lchip, p_sys_param);
            }
            if (ret != CTC_E_NONE)
            {
                goto error1;
            }
        }

    }
    _sys_usw_ipuc_update_ending(lchip, &old_info);

    return CTC_E_NONE;

error1:
    _sys_usw_ipuc_unbuild_ipda(lchip, p_sys_param, free_index);

error0:
    sal_memcpy(p_new_info, &old_info, db_size);
    if (old_bind_flag)
    {
        _sys_usw_ipuc_bind_nexthop(lchip, p_sys_param, 1);
    }
    return ret;
}

int32
_sys_usw_ipuc_add_tcam(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    int32 ret = CTC_E_NONE;
    ret = sys_usw_ipuc_add_tcam(lchip, p_sys_param);
    if (!ret && CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT))
    {
        sys_usw_ipuc_update_route_stats(lchip, p_sys_param->param.ip_ver, SYS_IPUC_CONFLICT_TCAM, 0);
    }
    if (ret && CTC_FLAG_ISSET(p_sys_param->param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM))
    {
        sys_ipuc_param_t temp_sys_param;
        sys_ipuc_info_t temp_info;
        uint32 tcam_index = 0;
        uint32 hash_index = 0;

        sal_memcpy(&temp_info, p_sys_param->info, IPUC_INFO_SIZE(SYS_IPUC_VER(p_sys_param->info)));
        sal_memcpy(&temp_sys_param, p_sys_param, sizeof(sys_ipuc_param_t));
        temp_sys_param.info = &temp_info;
        CTC_UNSET_FLAG(temp_sys_param.param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM);
        _sys_usw_ipuc_db_lookup(lchip, &temp_sys_param);
        if (temp_sys_param.info == NULL)
        {
            ret = CTC_E_NO_RESOURCE;
            return ret;
        }
        tcam_index = temp_sys_param.info->key_index;
        /* roll back for hash */
        ret = _sys_usw_ipuc_process_hash_key(lchip, &temp_sys_param, DO_ADD);
        hash_index = temp_sys_param.info->key_index;
        temp_sys_param.info->route_opt = DO_HASH;
        /* delete tcam */
        temp_sys_param.info->key_index = tcam_index;
        sys_usw_ipuc_del_tcam(lchip, &temp_sys_param);
        temp_sys_param.info->key_index = hash_index;
        CTC_UNSET_FLAG(temp_sys_param.info->route_flag, SYS_IPUC_FLAG_HOST_USE_LPM);
        CTC_UNSET_FLAG(temp_sys_param.info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT);
        sys_usw_ipuc_update_route_stats(lchip,  p_sys_param->param.ip_ver, SYS_IPUC_HASH, 0);
        sys_usw_ipuc_update_route_stats(lchip,  p_sys_param->param.ip_ver, SYS_IPUC_CONFLICT_TCAM, 1);
        ret = CTC_E_NO_RESOURCE;
    }
    return ret;
}

int32
_sys_usw_ipuc_add_hash(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    int32 ret = CTC_E_NONE;
    ret = _sys_usw_ipuc_process_hash_key(lchip, p_sys_param, DO_ADD);
    if (ret)
    {
        if (p_sys_param->param.l4_dst_port ||
            !CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[p_sys_param->param.ip_ver], SYS_TCAM_LOOKUP))   /* NAPT or there's no tcam to solve conflict */
        {
            return ret;
        }
        if (ret == CTC_E_HASH_CONFLICT && !p_usw_ipuc_master[lchip]->arc[p_sys_param->param.ip_ver])
        {
            return ret;
        }
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Add host route failed ret: %d. Than write to tcam. \r\n", ret);

        p_sys_param->info->route_opt = DO_TCAM;
        CTC_SET_FLAG(p_sys_param->info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT);
        ret = _sys_usw_ipuc_add_tcam(lchip, p_sys_param);
    }
    else
    {
        if (p_sys_param->param.l4_dst_port)
        {
            p_usw_ip_tunnel_master[lchip]->napt_hash_count++;
        }
        else
        {
            sys_usw_ipuc_update_route_stats(lchip,  p_sys_param->param.ip_ver, SYS_IPUC_HASH, 0);
        }
    }
    return ret;
}

int32
_sys_usw_ipuc_add_alpm(uint8 lchip, sys_ipuc_param_t* p_sys_param)
{
    uint8 auto_frag = 0;
    int32 ret = CTC_E_NONE;
    ret = CTC_E_NOT_EXIST;

    if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_add)
    {
        ret = MCHIP_IPUC(lchip)->nalpm2_add(lchip, p_sys_param, p_sys_param->info->ad_index, NULL);
    }
    else if (MCHIP_IPUC(lchip)->alpm_add)
    {
        ret = MCHIP_IPUC(lchip)->alpm_add(lchip, p_sys_param, p_sys_param->info->ad_index, NULL);
    }

    if (CTC_E_NO_RESOURCE == ret && DRV_IS_TSINGMA(lchip) && MCHIP_IPUC(lchip)->alpm_set_fragment_status && MCHIP_IPUC(lchip)->alpm_get_fragment_auto_enable &&
        MCHIP_IPUC(lchip)->alpm_merge)
    {
        MCHIP_IPUC(lchip)->alpm_get_fragment_auto_enable(lchip, &auto_frag);
        if (auto_frag)
        {
            ret = MCHIP_IPUC(lchip)->alpm_merge(lchip, p_sys_param->info->vrf_id, p_sys_param->param.ip_ver);
            if (ret)
            {
                MCHIP_IPUC(lchip)->alpm_set_fragment_status(lchip, p_sys_param->param.ip_ver, MERGE_NO_RESOURCE);
            }
            else
            {
                ret = MCHIP_IPUC(lchip)->alpm_add(lchip, p_sys_param, p_sys_param->info->ad_index, NULL);
            }
        }
    }

    if (!ret)
    {
        sys_usw_ipuc_update_route_stats(lchip,  p_sys_param->param.ip_ver, SYS_IPUC_ALPM, 0);
    }

    return ret;
}

int32
sys_usw_ipuc_add(uint8 lchip, ctc_ipuc_param_t* p_ctc_param_info)
{
    int32 ret = CTC_E_NONE;
    uint16 db_size = 0;
    uint8 opt = 0;
    uint8 ip_ver = p_ctc_param_info->ip_ver;
    sys_ipuc_param_t sys_param = {0};
    sys_nh_info_dsnh_t nhinfo;

    SYS_IPUC_INIT_CHECK;
    if(lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        return CTC_E_NONE;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&nhinfo, 0, sizeof(sys_nh_info_dsnh_t));
    sal_memset(&sys_param, 0, sizeof(sys_param));

    sal_memcpy(&sys_param.param, p_ctc_param_info, sizeof(ctc_ipuc_param_t));
    if(DRV_IS_AT(lchip))
    {
        sys_param.xdata = p_ctc_param_info->xdata;
    }

    /* 1. param check and debug out */
    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, &sys_param.param));
    SYS_IP_FUNC_DBG_DUMP((&sys_param.param));

    /* para check */
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, sys_param.param.nh_id, &nhinfo, 0));
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, &sys_param.param, 1, &nhinfo));
    SYS_IPUC_LOCK;
     /* 2. lookup sw node */
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO, 1);

    if (IS_MAX_MASKLEN(ip_ver, sys_param.param.masklen) && 0 == p_usw_ipuc_master[lchip]->host_lpm_mode)
    {
        CTC_ERROR_GOTO((_sys_usw_ipuc_host_pre_process(lchip, &sys_param)), ret, error0);
    }

    CTC_ERROR_GOTO((_sys_usw_ipuc_db_lookup(lchip, &sys_param)), ret, error0);
    if (sys_param.info)
    {
        sys_param.is_update = 1;
        CTC_ERROR_GOTO((_sys_usw_ipuc_update(lchip, &sys_param, &nhinfo)), ret, error0);
        CTC_RETURN_IPUC_UNLOCK(CTC_E_NONE);
    }

    if(!(p_usw_ipuc_master[lchip]->default_route_mode && 0 == sys_param.param.masklen))  /*Default route AD mdoe ,default route don't write Key*/
    {
        CTC_ERROR_GOTO((_sys_usw_ipuc_spec_check(lchip, &sys_param.param)), ret, error0);
        /* 3. Judge operation */
        CTC_ERROR_GOTO((_sys_usw_ipuc_get_store_position(lchip, &sys_param, &opt)), ret, error0);
    }

    db_size = IPUC_INFO_SIZE(ip_ver);
    sys_param.info = SYS_WB_MALLOC(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO,MEM_IPUC_MODULE,  db_size);
    if (NULL == sys_param.info)
    {
        CTC_ERROR_GOTO((CTC_E_NO_MEMORY), ret, error0);
    }
    sal_memset(sys_param.info, 0, db_size);

    _sys_usw_ipuc_param_to_info(lchip, &sys_param.param, sys_param.info);
    sys_param.info->route_opt = opt;
    if (sys_param.hash_conflict == 1)
    {
        CTC_SET_FLAG(sys_param.info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT);
    }
    
    /* 3. build ipda, include lpm ad profile */
    CTC_ERROR_GOTO(_sys_usw_ipuc_build_ipda(lchip, &sys_param, &nhinfo), ret, error1);

    /* 4. write ipda */
    if (MCHIP_IPUC(lchip)->write_ipda)
    {
        CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->write_ipda(lchip, &sys_param, 1, &nhinfo), ret, error2);
    }
    else
    {
        ret = CTC_E_INVALID_PTR;
        goto error2;
    }

    if(opt)/*Default route AD mdoe ,default route don't write Key*/
    {
        CTC_ERROR_GOTO(p_usw_ipuc_master[lchip]->ipuc_position_add[opt](lchip, &sys_param), ret, error2);
    }

    if(opt==DO_HASH && sys_param.info->l4_dst_port && 1 == (p_usw_ip_tunnel_master[lchip]->snat_tcam_count + p_usw_ip_tunnel_master[lchip]->snat_hash_count+p_usw_ip_tunnel_master[lchip]->napt_hash_count) &&
        MCHIP_XDATA(lchip)->func_en && !SYS_VCHIP_PP_IS_NOT_BASE(lchip))
    {
        /*Enable l4 src/dst port XPH*/
        CTC_ERROR_GOTO(MCHIP_XDATA(lchip)->func_en(lchip, SYS_XDATA_FUNC_NAT, 1, NULL),ret, error2);
    }


    if (ret == CTC_E_NONE)
    {
        ret = _sys_usw_ipuc_add_ending(lchip, &(sys_param));
    }
    else
    {
        goto error2;
    }

    SYS_IPUC_UNLOCK;
    return ret;
error2:
    _sys_usw_ipuc_unbuild_ipda(lchip, &sys_param, 1);
error1:
    SYS_WB_FREE(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO,sys_param.info);
error0:
    CTC_RETURN_IPUC_UNLOCK(ret);
}

int32
sys_usw_ipuc_remove(uint8 lchip, ctc_ipuc_param_t* p_ctc_param_info)
{
    uint8 ip_ver = p_ctc_param_info->ip_ver;
    sys_ipuc_param_t sys_param = {0};
    int32 ret = CTC_E_NONE;

    SYS_IPUC_INIT_CHECK;
    if(lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        return CTC_E_NONE;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memcpy(&sys_param.param, p_ctc_param_info, sizeof(ctc_ipuc_param_t));

    /* 1. param check and debug out */
    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, &sys_param.param));
    SYS_IP_FUNC_DBG_DUMP((&sys_param.param));

    /* para check */
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, &sys_param.param, 0, NULL));

    SYS_IPUC_LOCK;
    _sys_usw_ipuc_db_lookup(lchip, &sys_param);
    if(sys_param.info == NULL)
    {
        SYS_IPUC_UNLOCK;
        return CTC_E_NOT_EXIST;
    }

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO, 1);
    if ( (IS_MAX_MASKLEN(ip_ver, sys_param.param.masklen) &&
                    !CTC_FLAG_ISSET(sys_param.param.route_flag, CTC_IPUC_FLAG_HOST_USE_LPM) &&
                    CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_HASH_LOOKUP)) ||
                    sys_param.param.l4_dst_port)
    {
        /*do HOST remove*/
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "remove route from hash\n");
        /* lookup for ipuc entrise */
        if (CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT)
            || CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE))
        {
            goto DO_LPM;
        }

        ret = _sys_usw_ipuc_process_hash_key(lchip, &sys_param, DO_DEL);
        if (ret)
        {
            SYS_IPUC_UNLOCK;
            return ret;
        }

        if (sys_param.param.l4_dst_port)
        {
            p_usw_ip_tunnel_master[lchip]->napt_hash_count--;
            if(0 == (p_usw_ip_tunnel_master[lchip]->snat_tcam_count + p_usw_ip_tunnel_master[lchip]->snat_hash_count) +p_usw_ip_tunnel_master[lchip]->napt_hash_count &&
                MCHIP_XDATA(lchip)->func_en && !SYS_VCHIP_PP_IS_NOT_BASE(lchip))
            {
                /*Disable l4 src/dst port XPH*/
                MCHIP_XDATA(lchip)->func_en(lchip, SYS_XDATA_FUNC_NAT, 0, NULL);
            }
        }
        else
        {
            sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_HASH, 1);
        }

        ret = _sys_usw_ipuc_remove_ending(lchip, &sys_param);
        SYS_IPUC_UNLOCK;
        return(ret);
    }
    else
    {
DO_LPM:
        if (sys_param.info->route_opt == DO_ALPM)
        {
            if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_del)
            {
                ret = MCHIP_IPUC(lchip)->nalpm2_del(lchip, &(sys_param), NULL);
            }
            else if (MCHIP_IPUC(lchip)->alpm_del)
            {
                ret = MCHIP_IPUC(lchip)->alpm_del(lchip, &(sys_param));
            }

            if (!ret)
            {
                sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_ALPM, 1);
            }
        }
        else if(sys_param.info->route_opt == DO_TCAM)
        {
            ret = sys_usw_ipuc_del_tcam(lchip, &(sys_param));
            if (!ret && CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT))
            {
                sys_usw_ipuc_update_route_stats(lchip,  ip_ver, SYS_IPUC_CONFLICT_TCAM, 1);
            }
        }

        if (ret == CTC_E_NONE)
        {
            ret = _sys_usw_ipuc_remove_ending(lchip, &(sys_param));
        }
    }

    SYS_IPUC_UNLOCK;
    return(ret);
}

int32
_sys_usw_ipuc_resource_init(uint8 lchip)
{
    uint8 ip_ver = 0;
    uint8 tbl_type = 0;
    uint8 lookup_mode = 0;
    uint32 tbl_id = 0;
    uint32 entry_num = 0;
    uint32 tbl_size[MAX_ROUTE_MODE][3];

    sys_usw_ftm_query_lpm_tcam_init_size(lchip, (uint32 **)tbl_size);

    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM] = tbl_size[SYS_PRIVATE_MODE][0];
    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT] =
            tbl_size[SYS_PRIVATE_MODE][1] ? (tbl_size[SYS_PRIVATE_MODE][1] - tbl_size[SYS_PRIVATE_MODE][0]) : 0;
    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM] =
            tbl_size[SYS_PRIVATE_MODE][2] - (tbl_size[SYS_PRIVATE_MODE][1] ? tbl_size[SYS_PRIVATE_MODE][1] : tbl_size[SYS_PRIVATE_MODE][0]);
    /*if tcam bist cause ipv4 no entry, can not init sdk*/
    if(DRV_IS_TSINGMA(lchip) && (0 == p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM]))
    {
        return CTC_E_INIT_FAIL;
    }

    if (!p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM])
    {
        if (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT])
        {
            p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM] =
                    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT];
            p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT] = 0;
        }
    }

    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB] = tbl_size[SYS_PUBLIC_MODE][0];
    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB_SHORT] =
            tbl_size[SYS_PUBLIC_MODE][1] ? (tbl_size[SYS_PUBLIC_MODE][1] - tbl_size[SYS_PUBLIC_MODE][0]) : 0;
    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM_PUB] =
            tbl_size[SYS_PUBLIC_MODE][2] - (tbl_size[SYS_PUBLIC_MODE][1] ? tbl_size[SYS_PUBLIC_MODE][1] : tbl_size[SYS_PUBLIC_MODE][0]);
    if (!p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM_PUB])
    {
        if (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB_SHORT])
        {
            p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM_PUB] =
                    p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB_SHORT];
            p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB_SHORT] = 0;
        }
    }

    for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
    {   /* hash, napt_hash, lpm pipeline */
        for (tbl_type = SYS_TBL_HASH; tbl_type < SYS_TBL_TCAM; tbl_type++)
        {
            sys_usw_get_tbl_id(lchip, ip_ver, 1, tbl_type, &tbl_id, NULL);
            CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, tbl_id, &entry_num));
            if (entry_num > 0)
            {
                lookup_mode = tbl_type;

                CTC_BIT_SET(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], lookup_mode);
                p_usw_ipuc_master[lchip]->max_entry_num[ip_ver][tbl_type] = entry_num;
            }
        }

        sys_usw_get_tbl_id(lchip, ip_ver, 0, SYS_TBL_TCAM, &tbl_id, NULL);
        CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, tbl_id, &entry_num));
        if (entry_num > 0)
        {
            lookup_mode = SYS_TCAM_SA_LOOKUP;
            CTC_SET_FLAG(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], lookup_mode);
        }

        if (p_usw_ipuc_master[lchip]->max_entry_num[ip_ver][SYS_TBL_TCAM] || p_usw_ipuc_master[lchip]->max_entry_num[ip_ver][SYS_TBL_TCAM_SHORT])
        {
            lookup_mode = SYS_TCAM_LOOKUP;
            CTC_SET_FLAG(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], lookup_mode);
        }
        if (0 == p_usw_ipuc_master[lchip]->max_entry_num[ip_ver][SYS_TBL_TCAM] &&
            0 ==  p_usw_ipuc_master[lchip]->max_entry_num[ip_ver][SYS_TBL_TCAM_SHORT])
        {
            CTC_UNSET_FLAG(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], SYS_ALPM_LOOKUP);
        }

        if (p_usw_ipuc_master[lchip]->max_entry_num[ip_ver][SYS_TBL_TCAM_PUB])
        {
            lookup_mode = SYS_TCAM_PUB_LOOKUP;
            CTC_SET_FLAG(p_usw_ipuc_master[lchip]->lookup_mode[ip_ver], lookup_mode);
        }

        if (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB_SHORT])
        {
            lookup_mode = SYS_TCAM_PUB_SHORT_LOOKUP;
            CTC_SET_FLAG(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6], lookup_mode);
        }

        if (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT])
        {
            lookup_mode = SYS_TCAM_SHORT_LOOKUP;
            CTC_SET_FLAG(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6], lookup_mode);
            CTC_SET_FLAG(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6], SYS_TCAM_LOOKUP);
        }

        if (p_usw_ipuc_master[lchip]->lookup_mode[ip_ver])
        {
            p_usw_ipuc_master[lchip]->version_en[ip_ver] = TRUE;
        }
    }


    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_init_register(uint8 lchip)
{
    uint32 cmd = 0;
    uint32 field_value = 0;
    ds_t fib_neo_lpm_ctl;
    IpeRouteCtl_m ipe_route_ctl;
    ds_t ipe_lookup_route_ctl;
    ipv6_addr_t ipv6_addr;
    ipv6_addr_t ipv6_addr_mask;

    sal_memset(&fib_neo_lpm_ctl, 0, sizeof(fib_neo_lpm_ctl));


    /* other init */
    cmd = DRV_IOW(IpeIntfMapperCtl_t, IpeIntfMapperCtl_maxIpv4IcmpLengthEn_f);
    field_value = 0;
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));

    cmd = DRV_IOW(IpeIntfMapperCtl_t, IpeIntfMapperCtl_maxIpv6IcmpLengthEn_f);
    field_value = 0;
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));

    cmd = DRV_IOW(IpeIntfMapperCtl_t, IpeIntfMapperCtl_maxIcmpLengthEn_f);
    field_value = 0;
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));

    cmd = DRV_IOW(NeoLpmCtl_t, NeoLpmCtl_ipv4LpmBucketSelEn_f);
    field_value = 1;
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));

    sal_memset(&ipe_route_ctl, 0, sizeof(ipe_route_ctl));
    cmd = DRV_IOR(IpeRouteCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &ipe_route_ctl));
   /*default using as cloud sec*/
    SetIpeRouteCtl(V, cloudSecUseShareBit_f, &ipe_route_ctl, 1);
    SetIpeRouteCtl(V, vxlanCompatibilityMode_f, &ipe_route_ctl, 1);
    if(DRV_IS_AT(lchip))
    {
        SetIpeRouteCtl(V, tunnelEcmpNewMode_f, &ipe_route_ctl, 1);
    }
    /* configure Fooipda.selfDefType using exceptionSubIndex For PON*/
    SetIpeRouteCtl(V, dsIpExcepInfoShareMode_f, &ipe_route_ctl, 1);
    SetIpeRouteCtl(V, gExcepSubIndex_3_exceptionSubIndex_f, &ipe_route_ctl, CTC_L3PDU_ACTION_INDEX_IPDA);

    cmd = DRV_IOW(IpeRouteCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &ipe_route_ctl));

    /*configure default ipv6 martian address*/
    sal_memset(&ipe_lookup_route_ctl, 0, sizeof(ipe_lookup_route_ctl));
    cmd = DRV_IOR(IpeLookupRouteCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &ipe_lookup_route_ctl));
    ipv6_addr[0] = 0;
    ipv6_addr[1] = 0;
    ipv6_addr[2] = 0;
    ipv6_addr[3] = 0x3ffe0000;
    SetIpeLookupRouteCtl(A, martianAddr_f, ipe_lookup_route_ctl, ipv6_addr);
    ipv6_addr_mask[0] = 0xffffffff;
    ipv6_addr_mask[1] = 0xffffffff;
    ipv6_addr_mask[2] = 0xffffffff;
    ipv6_addr_mask[3] = 0xffffffff;
    SetIpeLookupRouteCtl(A, martianAddrMask_f, ipe_lookup_route_ctl, ipv6_addr_mask);
    cmd = DRV_IOW(IpeLookupRouteCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &ipe_lookup_route_ctl));

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_init_default_entry(uint8 lchip)
{
    ds_t fib_engine_lookup_result_ctl;
    uint32 cmd = 0;
    uint32 field_value = 0;
    uint32 offset = 0;
    int32 ret = CTC_E_NONE;
    uint8 alloc_opf_flag[MAX_CTC_IP_VER] = {0};
    uint8 ip_ver = 0;
    uint8 default_route_mode = p_usw_ipuc_master[lchip]->default_route_mode? 1 : 0 ;
    uint16 vrfid = 0;
    uint16 max_vrf_num = p_usw_ipuc_master[lchip]->default_route_mode ? MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID)+1 : 1;

    sal_memset(&fib_engine_lookup_result_ctl, 0, sizeof(fib_engine_lookup_result_ctl));
    /* deal with default entry*/
    for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
    {
        if (!p_usw_ipuc_master[lchip]->version_en[ip_ver])
        {
            continue;
        }
        if(lchip != p_usw_ipuc_master[lchip]->master_lchip)
        {
            CTC_ERROR_GOTO(sys_usw_ftm_alloc_table_offset_from_position(lchip, DsIpDa_t, 1, max_vrf_num, p_usw_ipuc_master[lchip]->default_base[ip_ver]), ret, error0);
            offset = p_usw_ipuc_master[lchip]->default_base[ip_ver];
        }
        else
        {
            CTC_ERROR_GOTO(sys_usw_ftm_alloc_table_offset(lchip, DsIpDa_t, 1, max_vrf_num, 1, &offset), ret, error0);
            p_usw_ipuc_master[lchip]->default_nhid[ip_ver] = SYS_NH_RESOLVED_NHID_FOR_DROP;
            p_usw_ipuc_master[lchip]->default_base[ip_ver] = offset;
        }

        alloc_opf_flag[ip_ver] = 1;
        SYS_IP_CHECK_VERSION_ENABLE(ip_ver);
        for(vrfid = 0; vrfid < max_vrf_num; vrfid++)
        {
            CTC_ERROR_GOTO(_sys_usw_ipuc_add_default_entry(lchip, ip_ver, vrfid, SYS_NH_RESOLVED_NHID_FOR_DROP, default_route_mode),ret, error0);
        }

        cmd = DRV_IOR(FibEngineLookupResultCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &fib_engine_lookup_result_ctl),ret, error0);
        field_value = p_usw_ipuc_master[lchip]->default_route_mode ? 0 : 1;/* See ctc_ipuc_global_cfg_t default_route_mode */
        if (CTC_IP_VER_4 == ip_ver)
        {
            cmd = DRV_IOW(FibEngineLookupResultCtl_t, DRV_ENTRY_FLAG);

            /* ucast da default entry base */
            SetFibEngineLookupResultCtl(V, gIpv4UcastLookupResultCtl_defaultEntryBase_f, fib_engine_lookup_result_ctl, offset);
            SetFibEngineLookupResultCtl(V, gIpv4UcastLookupResultCtl_defaultEntryEn_f, fib_engine_lookup_result_ctl, 1);

            /* ucast rpf sa default entry base */
            SetFibEngineLookupResultCtl(V, gIpv4RpfLookupResultCtl_defaultEntryBase_f, fib_engine_lookup_result_ctl, offset);
            SetFibEngineLookupResultCtl(V, gIpv4RpfLookupResultCtl_defaultEntryEn_f, fib_engine_lookup_result_ctl, 1);
            SetFibEngineLookupResultCtl(V, gIpv4RpfLookupResultCtl_defaultEntryType_f, fib_engine_lookup_result_ctl, field_value);
            SetFibEngineLookupResultCtl(V, gIpv4UcastLookupResultCtl_defaultEntryType_f, fib_engine_lookup_result_ctl, field_value);

            CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &fib_engine_lookup_result_ctl),ret, error0);
        }
        else if (CTC_IP_VER_6 == ip_ver)
        {
            cmd = DRV_IOW(FibEngineLookupResultCtl_t, DRV_ENTRY_FLAG);

            /* ucast da default entry base */
            SetFibEngineLookupResultCtl(V, gIpv6UcastLookupResultCtl_defaultEntryBase_f, fib_engine_lookup_result_ctl, offset);
            SetFibEngineLookupResultCtl(V, gIpv6UcastLookupResultCtl_defaultEntryEn_f, fib_engine_lookup_result_ctl, 1);

            /* ucast rpf sa default entry base */
            SetFibEngineLookupResultCtl(V, gIpv6RpfLookupResultCtl_defaultEntryBase_f, fib_engine_lookup_result_ctl, offset);
            SetFibEngineLookupResultCtl(V, gIpv6RpfLookupResultCtl_defaultEntryEn_f, fib_engine_lookup_result_ctl, 1);
            SetFibEngineLookupResultCtl(V, gIpv6RpfLookupResultCtl_defaultEntryType_f, fib_engine_lookup_result_ctl, field_value);
            SetFibEngineLookupResultCtl(V, gIpv6UcastLookupResultCtl_defaultEntryType_f, fib_engine_lookup_result_ctl, field_value);

            CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &fib_engine_lookup_result_ctl),ret, error0);
        }
    }

    return CTC_E_NONE;
error0:
    for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
    {
        if (alloc_opf_flag[ip_ver])
        {
            sys_usw_ftm_free_table_offset(lchip, DsIpDa_t, 0, max_vrf_num, p_usw_ipuc_master[lchip]->default_base[ip_ver]);
        }
    }

    return ret;
}

int32
_sys_usw_ipuc_get_xdata_withcheck(uint8 lchip,ctc_xdata_t* p_xdata ,sys_ipuc_xdata_info_t* p_xdata_info ,DsIpDa_m* p_dsipda,uint8 is_check)
{
    CTC_ERROR_RETURN(DRV_FROM_AT(lchip)? CTC_E_NONE: CTC_E_NOT_SUPPORT);
    if(CTC_XDATA_PROF_TYPE_DSIPDA != p_xdata->type || 0 != p_xdata->prof_id)
    {
       SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Xdata type or prof-id error\n");
       return CTC_E_INVALID_PARAM;
    }

    CTC_ERROR_RETURN(MCHIP_XDATA(lchip)->prof_get_info(lchip, p_xdata, is_check));
    CTC_ERROR_RETURN(_sys_usw_ipuc_xdata_mapping(p_xdata, p_xdata_info, is_check));

    if(!is_check)
    {
        return CTC_E_NONE;
    }

    if(0 != GetDsIpDa(V, u3Type_f, p_dsipda) && CTC_IS_BIT_SET(p_xdata_info->flag,SYS_IPUC_XDATA_U3G1))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Xdata field confilict\n");
        return CTC_E_INVALID_PARAM;
    }

    if(((0 != GetDsIpDa(V, u2Type_f, p_dsipda))      ||
        (0 != GetDsIpDa(V, rpfCheckEn_f, p_dsipda))   ||
        (0 != GetDsIpDa(V, icmpCheckEn_f, p_dsipda))) &&
       (CTC_IS_BIT_SET(p_xdata_info->flag,SYS_IPUC_XDATA_U2G1)))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Xdata field confilict\n");
        return CTC_E_INVALID_PARAM;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_xdata_mapping(ctc_xdata_t* p_xdata,sys_ipuc_xdata_info_t* p_xdata_info,uint8 is_set)
{
    uint8 loop_i = 0;
    uint32 width = 0;
    uint32 offset = 0;
    uint32 field_value = 0;

    for(loop_i = 0 ;(loop_i < p_xdata->num); loop_i++)
    {
        width  = p_xdata->fields[loop_i].width;
        offset = p_xdata->fields[loop_i].offset;

        if(SYS_IPUC_XDATA_TRUNK0(offset, width))
        {
            CTC_BIT_SET(p_xdata_info->flag, SYS_IPUC_XDATA_AUX);
        }
        else if(SYS_IPUC_XDATA_TRUNK1(offset, width))
        {
            CTC_BIT_SET(p_xdata_info->flag, SYS_IPUC_XDATA_U3G1);
        }
        else if(SYS_IPUC_XDATA_TRUNK2(offset, width))
        {
            CTC_BIT_SET(p_xdata_info->flag, SYS_IPUC_XDATA_U2G1);
        }
        else
        {
            return CTC_E_NOT_SUPPORT;
        }

        if(is_set)
        {
            field_value  = p_xdata->fields[loop_i].data;
            SYS_USW_SET_XDATA(width,offset,field_value,p_xdata_info->ds_value);
        }
        else
        {
            SYS_USW_GET_XDATA(width,offset,field_value,p_xdata_info->ds_value)
            p_xdata->fields[loop_i].data = field_value;
        }
    }

    return CTC_E_NONE;
}

int32
sys_usw_ipuc_host_ftm_cb(uint8 lchip, sys_ftm_specs_info_t* specs_info);

int32
sys_usw_ipuc_alpm_ftm_cb(uint8 lchip, sys_ftm_specs_info_t* specs_info);

int32
sys_usw_ipuc_dump_db(uint8 lchip, sal_file_t p_f, ctc_global_dump_db_t* p_dump_param);

#define __6_SLAVE_LCHIP__

int32
_sys_usw_ipuc_update_slave_ipda(uint8 lchip, sys_ipuc_info_t* p_ipuc_info, void* p_dsipda, uint8 use_dsfwd)
{
    uint32 cmd = 0;
    uint32 fwd_offset = 0;

    if (use_dsfwd)
    {
        /*update ad from merge dsfwd to using dsfwd*/
        CTC_ERROR_RETURN(sys_usw_nh_get_dsfwd_offset(lchip, p_ipuc_info->nh_id, &fwd_offset, 0, CTC_FEATURE_IPUC));
        if(DRV_IS_TSINGMA(lchip)|| DRV_IS_DUET2(lchip))
        {
            SetDsIpDa(V, dsFwdPtrOrEcmpGroupId_f, p_dsipda, fwd_offset);
        }
        else
        {
            SetDsIpDa(V, u1_g3_dsFwdPtr_f, p_dsipda, fwd_offset);
        }
    }
    else
    {
        sys_ipuc_param_t sys_param;
        sys_nh_info_dsnh_t dsnh_info;
        sal_memset(&sys_param, 0, sizeof(sys_param));
        sal_memset(&dsnh_info, 0, sizeof(sys_nh_info_dsnh_t));
        _sys_usw_ipuc_info_to_param(lchip, &sys_param.param, p_ipuc_info);
        sys_param.info = p_ipuc_info;

        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, p_ipuc_info->nh_id, &dsnh_info, 0));
        CTC_ERROR_RETURN(_sys_usw_ipuc_build_ipda_nexthop(lchip, &sys_param, &dsnh_info, p_dsipda));
    }
    cmd = DRV_IOW(DsIpDa_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_dsipda);

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_hash_free_node_data(sys_ipuc_info_t *p_ipuc_info, void* user_data)
{
    sys_nh_update_dsnh_param_t update_dsnh;
    ctc_hash_t* p_hash = NULL;
    uint32 hash_idx = 0;
    uint8 lchip = *(uint8*)user_data;

    p_hash = p_usw_ipuc_master[lchip]->fib_hash[SYS_IPUC_VER(p_ipuc_info)];
    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH))
    {
        hash_idx = p_hash->hash_key(p_ipuc_info) % (p_hash->block_size * p_hash->block_num);
        hash_idx |= ((SYS_IPUC_VER(p_ipuc_info) == CTC_IP_VER_6) ? 0x80000000 :0);
        update_dsnh.data = p_ipuc_info;
        update_dsnh.updateAd = sys_usw_ipuc_update_ipda;
        update_dsnh.chk_data = hash_idx;
        update_dsnh.bind_feature = CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_MERGE_KEY) ? CTC_FEATURE_IPUC : 0;
        sys_usw_nh_bind_dsfwd_cb(lchip, p_ipuc_info->nh_id, &update_dsnh);
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_init_slave(uint8 lchip, ctc_ipuc_global_cfg_t* p_ipuc_global_cfg)
{
    uint8 master_lchip = p_ipuc_global_cfg->master_lchip;
    uint16 loop_i = 0;
    uint32 cmd = 0;
    uint32 field_value = 0;
    ds_t fib_engine_lookup_ctl;

    LCHIP_CHECK(lchip);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&fib_engine_lookup_ctl, 0, sizeof(fib_engine_lookup_ctl));

    if(NULL != p_usw_ipuc_master[lchip])
    {
        return CTC_E_NONE;
    }

    if(!p_usw_ipuc_master[master_lchip])
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Master lchip must init first!! \n");
        return CTC_E_NOT_READY;
    }

    if(MCHIP_FEATURE_PP_EN(master_lchip,CTC_FEATURE_IPUC) || MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Not support pp mode when ipuc master chip valid!!\n");
        return CTC_E_NOT_SUPPORT;
    }

    p_usw_ipuc_master[lchip] = p_usw_ipuc_master[master_lchip];
    p_usw_ipuc_master[lchip]->slave_lchip_cnt++;

    if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_init)
        {
            CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->nalpm2_init(lchip, p_ipuc_global_cfg, 0));
        }
        else if (MCHIP_IPUC(lchip)->alpm_init)
        {
            CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->alpm_init(lchip, p_ipuc_global_cfg, 0));
        }
    }

    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING )
    {
        SYS_IPUC_LOCK;
        ctc_hash_traverse(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_4], (hash_traversal_fn)_sys_usw_ipuc_hash_free_node_data, &lchip);
        ctc_hash_traverse(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_6], (hash_traversal_fn)_sys_usw_ipuc_hash_free_node_data, &lchip);
        SYS_IPUC_UNLOCK;
    }

    cmd = DRV_IOR(FibEngineLookupCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(master_lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &fib_engine_lookup_ctl));
    cmd = DRV_IOW(FibEngineLookupCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &fib_engine_lookup_ctl));

    cmd = DRV_IOW(IpeRouteCtl_t, IpeRouteCtl_rpfCheckAgainstPort_f);
    field_value = p_ipuc_global_cfg->rpf_check_port;
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));

    cmd = DRV_IOW(DsRpf_t, DsRpf_moreRpfCheckMode_f);
    field_value = p_ipuc_global_cfg->rpf_fail_to_cpu ? 2 : 0;
    for(loop_i = 0 ;loop_i < DRV_TABLE_MAX_INDEX(lchip, DsRpf_t); loop_i++)
    {
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, loop_i, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));
    }

    if(DRV_IS_TSINGMA(lchip))
    {
        cmd = DRV_IOR(LpmPipelineIfCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(master_lchip, 0, cmd, &field_value));
        cmd = DRV_IOW(LpmPipelineIfCtl_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &field_value));

        cmd = DRV_IOR(FibEngineReserved_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(master_lchip, 0, cmd, &field_value));
        cmd = DRV_IOW(FibEngineReserved_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &field_value));
    }

    /*init ipuc related register*/
    CTC_ERROR_RETURN(_sys_usw_ipuc_init_register(lchip));

    /*init default entry*/
    CTC_ERROR_RETURN(_sys_usw_ipuc_init_default_entry(lchip));

    sys_usw_ftm_register_callback(lchip, CTC_FTM_SPEC_IPUC_HOST,
                sys_usw_ipuc_host_ftm_cb);
    sys_usw_ftm_register_callback(lchip, CTC_FTM_SPEC_IPUC_LPM,
                sys_usw_ipuc_alpm_ftm_cb);


    CTC_ERROR_RETURN(sys_usw_dump_db_register_cb(lchip, CTC_FEATURE_IPUC, sys_usw_ipuc_dump_db));
    SYS_CB_REGISTER(lchip, SYS_CB_LDP_UPDATE_L3, sys_usw_ipuc_update_ldp_dsip);
    SYS_CB_REGISTER(lchip, SYS_CB_NHID_UPDATE_L3, sys_usw_ipuc_update_dsip_by_nhid);
    #ifdef CTC_WB_RT_SYNC
    CTC_ERROR_RETURN(SYS_CB_REGISTER(lchip, SYS_CB_IPUC_UPDATE_HASH, _sys_usw_ipuc_update_hash));
    #endif
    sys_usw_mchip_set_feature_en(lchip,CTC_FEATURE_IPUC);

    return CTC_E_NONE;
}

#define __7_WARMBOOT__

int32
_sys_usw_ipuc_wb_mapping_info(uint8 lchip, sys_wb_ipuc_info_t *p_wb_ipuc_info, sys_ipuc_info_t *p_ipuc_info, uint8 sync)
{
    uint8 addr_size = 0;

    if (sync)
    {
        sal_memset(&p_wb_ipuc_info->lpm_info, 0, sizeof(p_wb_ipuc_info->lpm_info));
        p_wb_ipuc_info->rsv = 0;
        p_wb_ipuc_info->masklen = p_ipuc_info->masklen;
        p_wb_ipuc_info->vrf_id = p_ipuc_info->vrf_id;

        addr_size = (SYS_IPUC_VER(p_ipuc_info) == CTC_IP_VER_4) ? sizeof(ip_addr_t): sizeof(ipv6_addr_t);
        sal_memcpy(p_wb_ipuc_info->ip, &(p_ipuc_info)->ip, addr_size);

        if (SYS_IPUC_VER(p_ipuc_info) == CTC_IP_VER_4)
        {
            sal_memset(&p_wb_ipuc_info->ip[1], 0, sizeof(uint32) * 3);
        }
        p_wb_ipuc_info->route_flag = p_ipuc_info->route_flag;
        p_wb_ipuc_info->nh_id = p_ipuc_info->nh_id;
        p_wb_ipuc_info->ad_index = p_ipuc_info->ad_index;
        p_wb_ipuc_info->key_index = p_ipuc_info->key_index;
        p_wb_ipuc_info->l4_dst_port = p_ipuc_info->l4_dst_port;
        p_wb_ipuc_info->route_opt = p_ipuc_info->route_opt;

        if (DO_ALPM != p_ipuc_info->route_opt)
        {
            return CTC_E_NONE;
        }

        p_wb_ipuc_info->lpm_info.nalpm_info.sram_idx = p_ipuc_info->sram_idx;
        p_wb_ipuc_info->lpm_info.nalpm_info.sub_bkt = p_ipuc_info->sub_bkt;
        p_wb_ipuc_info->lpm_info.nalpm_info.snake_idx = p_ipuc_info->snake_idx;
        p_wb_ipuc_info->lpm_info.nalpm_info.entry_offset = p_ipuc_info->entry_offset;
        p_wb_ipuc_info->lpm_info.nalpm_info.tcam_idx = p_ipuc_info->tcam_idx;
        
        if(DRV_IS_DUET2(lchip))
        {
            ctc_ipuc_param_t ctc_param;
            sal_memset(&ctc_param, 0, sizeof(ctc_ipuc_param_t));
            _sys_usw_ipuc_info_to_param(lchip, &ctc_param, p_ipuc_info);
            /*sys_duet2_calpm_get_wb_info(lchip, &ctc_param, &p_wb_ipuc_info->lpm_info);*/
            if (MCHIP_IPUC(lchip)->alpm_get_wb_info)
            {
                CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->alpm_get_wb_info(lchip, &ctc_param, &p_wb_ipuc_info->lpm_info));
            }
        }
        
    }
    else
    {
        DsIpDa_m dsipda;
        int32 cmd = 0;

        sal_memset(&dsipda, 0, sizeof(DsIpDa_m));

        p_ipuc_info->nh_id = p_wb_ipuc_info->nh_id;
        p_ipuc_info->ad_index = p_wb_ipuc_info->ad_index;
        p_ipuc_info->key_index = p_wb_ipuc_info->key_index;
        p_ipuc_info->vrf_id = p_wb_ipuc_info->vrf_id;
        p_ipuc_info->route_flag = p_wb_ipuc_info->route_flag;
        p_ipuc_info->masklen = p_wb_ipuc_info->masklen;
        p_ipuc_info->l4_dst_port = p_wb_ipuc_info->l4_dst_port;
        p_ipuc_info->route_opt = p_wb_ipuc_info->route_opt;

        p_ipuc_info->sram_idx = p_wb_ipuc_info->lpm_info.nalpm_info.sram_idx;
        p_ipuc_info->sub_bkt = p_wb_ipuc_info->lpm_info.nalpm_info.sub_bkt;
        p_ipuc_info->snake_idx = p_wb_ipuc_info->lpm_info.nalpm_info.snake_idx;
        p_ipuc_info->entry_offset = p_wb_ipuc_info->lpm_info.nalpm_info.entry_offset;
        p_ipuc_info->tcam_idx = p_wb_ipuc_info->lpm_info.nalpm_info.tcam_idx;

        addr_size = (SYS_IPUC_VER(p_ipuc_info) == CTC_IP_VER_4) ? sizeof(ip_addr_t): sizeof(ipv6_addr_t);
        sal_memcpy(&(p_ipuc_info)->ip, &(p_wb_ipuc_info)->ip, addr_size);

        cmd = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_wb_ipuc_info->ad_index, cmd, &dsipda);

        if (!GetDsIpDa(V, u2Type_f, &dsipda) && GetDsIpDa(V, rpfCheckEn_f, &dsipda))
        {
            p_ipuc_info->rpf_id = GetDsIpDa(V, rpfIfId_f, &dsipda);
            p_ipuc_info->rpf_mode = GetDsIpDa(V, rpfCheckMode_f, &dsipda);
        }

        if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_RPF_CHECK) && p_ipuc_info->rpf_mode == SYS_RPF_CHK_MODE_PROFILE
            && p_ipuc_info->rpf_id >= SYS_RPF_PROFILE_START_INDEX && !CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NH_RPF_EN))
        {
            CTC_ERROR_RETURN(sys_usw_rpf_restore_profile(lchip, p_ipuc_info->rpf_id));
        }
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_wb_sync_info_func(sys_ipuc_info_t *p_ipuc_info, void *user_data)
{
    uint32 max_entry_cnt = 0;
    sys_wb_ipuc_info_t  *p_wb_ipuc_info;
    sys_traverse_t *data = (sys_traverse_t *)user_data;
    ctc_wb_data_t *wb_data = (ctc_wb_data_t *)(data->data);
    uint8 lchip = (uint8)(data->value1);

    max_entry_cnt =  wb_data->buffer_len / (wb_data->key_len + wb_data->data_len);
    if (!ctc_wb_get_rt_en(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO))
    {
        p_wb_ipuc_info = (sys_wb_ipuc_info_t *)wb_data->buffer + wb_data->valid_cnt;
        CTC_ERROR_RETURN(_sys_usw_ipuc_wb_mapping_info(lchip, p_wb_ipuc_info, p_ipuc_info, 1));
    }
    if (++wb_data->valid_cnt == max_entry_cnt)
    {
        CTC_ERROR_RETURN(ctc_wb_add_entry(wb_data));
        wb_data->valid_cnt = 0;
    }

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_rebuild_ipuc_entry(uint8 lchip,  sys_ipuc_info_t *p_ipuc_info,sys_wb_ipuc_info_t *p_wb_ipuc_info)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    DsIpDa_m  dsipda;
    sys_ipuc_ad_spool_t ipuc_ad_new;
    sys_nh_update_dsnh_param_t update_dsnh;
    sys_ipuc_param_t sys_param;

    sal_memset(&ipuc_ad_new, 0, sizeof(sys_ipuc_ad_spool_t));
    sal_memset(&sys_param, 0, sizeof(sys_ipuc_param_t));

    _sys_usw_ipuc_info_to_param(lchip, &sys_param.param, p_ipuc_info);
    sys_param.info = p_ipuc_info;

    if (CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH))
    {
        uint32 hash_idx = 0;
        ctc_hash_t* p_hash = NULL;
        p_hash = p_usw_ipuc_master[lchip]->fib_hash[SYS_IPUC_VER(p_ipuc_info)];
        hash_idx = p_hash->hash_key(p_ipuc_info) % (p_hash->block_size * p_hash->block_num);
        hash_idx |= ((SYS_IPUC_VER(p_ipuc_info) == CTC_IP_VER_6) ? 0x80000000 :0);
        update_dsnh.data = p_ipuc_info;
        update_dsnh.updateAd = sys_usw_ipuc_update_ipda;
        update_dsnh.chk_data = hash_idx;
        update_dsnh.bind_feature = CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_MERGE_KEY) ? CTC_FEATURE_IPUC : 0;
        sys_usw_nh_bind_dsfwd_cb(lchip, p_ipuc_info->nh_id, &update_dsnh);
    }

    /*for vxlan ldp tunne update underlay*/
    if (DRV_FROM_TM(lchip) && p_ipuc_info->nh_id)
    {
        sys_nh_info_dsnh_t dsnh_info;
        sal_memset(&dsnh_info, 0, sizeof(dsnh_info));
        ret = (sys_usw_nh_get_nhinfo(lchip, p_ipuc_info->nh_id, &dsnh_info, 0));
        if ((ret == CTC_E_NONE) && ((dsnh_info.nh_entry_type == SYS_NH_TYPE_OVERLAY)
            || (dsnh_info.nh_entry_type == SYS_NH_TYPE_SRV6)))
        {
            ipuc_ad_new.param.overlay_nh = p_ipuc_info->nh_id;
        }
        if((ret == CTC_E_NONE) && dsnh_info.logic_port && (dsnh_info.nh_entry_type == SYS_NH_TYPE_OVERLAY || dsnh_info.bind_ldp))
        {
            ipuc_ad_new.param.ldp = dsnh_info.logic_port;
        }
        else if ((ret == CTC_E_NONE) && (dsnh_info.nh_entry_type == SYS_NH_TYPE_SRV6))
        {
            ipuc_ad_new.param.ldp = SYS_COM_LDP_SRH_ID(dsnh_info.tunnel_id);
        }
    }

    if(!CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_DEFAULT)) /*Only default route AD mode will set this flag*/
    {
        /*add ad spool*/
        ipuc_ad_new.param.p_ad = &dsipda;
        cmd = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);
        ipuc_ad_new.ad_index = p_ipuc_info->ad_index;
        ipuc_ad_new.param.lchip = lchip;

        ret = ctc_spool_add2(p_usw_ipuc_master[lchip]->ad_spool, &ipuc_ad_new, NULL, NULL);
        if (ret < 0)
        {
            CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "ctc_spool_add error! ret: %d.\n", ret);
            return ret;
        }
    }

    /*add calpm route once again*/
    if (p_ipuc_info->route_opt == DO_ALPM)
    {
        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_add)
        {
            ret = MCHIP_IPUC(lchip)->nalpm2_add(lchip, &sys_param, p_ipuc_info->ad_index, (void*)&p_wb_ipuc_info->lpm_info);
            if (ret)
            {
                CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "add alpm error! ret: %d.\n", ret);
                return ret;
            }
            sys_usw_ipuc_update_route_stats(lchip,  SYS_IPUC_VER(p_ipuc_info), SYS_IPUC_ALPM, 0);
        }
        else if (MCHIP_IPUC(lchip)->alpm_add)
        {
            ret = MCHIP_IPUC(lchip)->alpm_add(lchip, &sys_param, p_ipuc_info->ad_index, (void*)&p_wb_ipuc_info->lpm_info);
            if (ret)
            {
                CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "add alpm error! ret: %d.\n", ret);
                return ret;
            }
            sys_usw_ipuc_update_route_stats(lchip,  SYS_IPUC_VER(p_ipuc_info), SYS_IPUC_ALPM, 0);
        }
    }/*alloc Tcam key index from position*/
    else if (DO_TCAM == p_ipuc_info->route_opt)
    {
            sys_ipuc_tcam_data_t tcam_data = {0};

        tcam_data.opt_type = DO_ADD;
        tcam_data.key_index = p_ipuc_info->key_index;
        tcam_data.key_type = SYS_IPUC_TCAM_FLAG_TCAM;
        tcam_data.ipuc_param = &sys_param.param;
        tcam_data.info = (void*)p_ipuc_info;

        ret = MCHIP_IPUC(lchip)->alloc_tcam_key_index(lchip, &tcam_data);
        if (ret)
        {
            CTC_WB_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "sys_usw_ipuc_alloc_tcam_key_index %u error! ret: %d.\n", p_ipuc_info->key_index, ret);
            return ret;
        }
        if (CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_HASH_CONFLICT))
        {
            sys_usw_ipuc_update_route_stats(lchip, sys_param.param.ip_ver, SYS_IPUC_CONFLICT_TCAM, 0);
        }
        //SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "alloc sort key index from %u.\n", p_ipuc_info->key_index);
    }
    else if(DO_HASH == p_ipuc_info->route_opt)
    {
        /* HASH */
        if (!CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_NAPT))
        {
            p_usw_ipuc_master[lchip]->route_stats[sys_param.param.ip_ver][SYS_IPUC_HASH]++;
        }
    }
    _sys_usw_ipuc_add_ending(lchip, &sys_param);
    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_restore_ipuc_info(uint8 lchip)
{
     uint32 entry_cnt = 0;
     uint8 db_size = 0;
     int32 ret = CTC_E_NONE;
     ctc_wb_query_t wb_query;
     sys_ipuc_info_t *p_ipuc_info;
     sys_wb_ipuc_info_t  wb_ipuc_info;

     sal_memset(&wb_ipuc_info, 0, sizeof(sys_wb_ipuc_info_t));

    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);
     /*restore  ipuc_info*/
    CTC_WB_INIT_QUERY_T((&wb_query),sys_wb_ipuc_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO);

    CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));
        sal_memcpy((uint8*)&wb_ipuc_info, (uint8*)(wb_query.buffer) + entry_cnt * (wb_query.key_len + wb_query.data_len), wb_query.key_len + wb_query.data_len);
        entry_cnt++;

        db_size = IPUC_INFO_SIZE(SYS_IPUC_VER(&wb_ipuc_info));
        p_ipuc_info = mem_malloc(MEM_IPUC_MODULE,  db_size);
        if (NULL == p_ipuc_info)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_ipuc_info, 0, db_size);

        ret = _sys_usw_ipuc_wb_mapping_info(lchip, &wb_ipuc_info, p_ipuc_info, 0);
        if (ret)
        {
            mem_free(p_ipuc_info);
            continue;
        }
        _sys_usw_ipuc_rebuild_ipuc_entry( lchip,  p_ipuc_info,&wb_ipuc_info);
    CTC_WB_QUERY_ENTRY_END((&wb_query));

    if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_wb_set_ad_info)
        {
            MCHIP_IPUC(lchip)->nalpm2_wb_set_ad_info(lchip);
        }
        else if(MCHIP_IPUC(lchip)->alpm_wb_set_ad_info)
        {
            MCHIP_IPUC(lchip)->alpm_wb_set_ad_info(lchip);
        }
    }

done:
     CTC_WB_FREE_BUFFER(wb_query.buffer);
     return CTC_E_NONE;

}
int32
_sys_usw_ipuc_restore_ipuc_info2(uint8 lchip)
{
     uint32 entry_cnt = 0;
     int32 ret = CTC_E_NONE;
     ctc_wb_query_t wb_query;
     sys_ipuc_info_t *p_ipuc_info;
     sys_wb_ipuc_info_t  wb_ipuc_info;

     sal_memset(&wb_ipuc_info, 0, sizeof(sys_wb_ipuc_info_t));

    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);
     /*restore  ipuc_info*/
     CTC_WB_INIT_QUERY_T((&wb_query),sys_wb_ipuc_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO);
     CTC_WB_QUERY_ENTRY_BEGIN2((&wb_query));
         p_ipuc_info = (sys_ipuc_info_t *)wb_query.buffer + entry_cnt;
         wb_ipuc_info.lpm_info.nalpm_info.sram_idx = p_ipuc_info->sram_idx;
         wb_ipuc_info.lpm_info.nalpm_info.sub_bkt = p_ipuc_info->sub_bkt;
         wb_ipuc_info.lpm_info.nalpm_info.snake_idx = p_ipuc_info->snake_idx;
         wb_ipuc_info.lpm_info.nalpm_info.entry_offset = p_ipuc_info->entry_offset;
         wb_ipuc_info.lpm_info.nalpm_info.tcam_idx = p_ipuc_info->tcam_idx;

         _sys_usw_ipuc_rebuild_ipuc_entry( lchip,  p_ipuc_info,&wb_ipuc_info);
    CTC_WB_QUERY_ENTRY_END2((&wb_query));

    if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_wb_set_ad_info)
        {
            MCHIP_IPUC(lchip)->nalpm2_wb_set_ad_info(lchip);
        }
        else if(MCHIP_IPUC(lchip)->alpm_wb_set_ad_info(lchip))
        {
            MCHIP_IPUC(lchip)->alpm_wb_set_ad_info(lchip);
        }
    }

done:
    CTC_WB_FREE_BUFFER(wb_query.buffer);
    return CTC_E_NONE;
}


int32
_sys_usw_ipuc_wb_init(uint8 lchip)
{
    ctc_wb_appid_t  appid;
    sal_memset(&appid, 0, sizeof(appid));

    appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_MASTER) ;
    appid.entry_num = 1;
    appid.entry_size  = sizeof(sys_wb_ipuc_master_t);
    appid.rt_en = 0;
    ctc_wb_add_appid( lchip, &appid);

    appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO) ;
    appid.entry_num = sys_usw_ftm_get_spec(lchip, CTC_FTM_SPEC_IPUC_HOST) + sys_usw_ftm_get_spec(lchip, CTC_FTM_SPEC_IPUC_ND)
        + sys_usw_ftm_get_spec(lchip, CTC_FTM_SPEC_IPUC_LPM) + sys_usw_ftm_get_spec(lchip, CTC_FTM_SPEC_IPUC_LPMv6);

#ifdef CTC_WB_RT_SYNC
    appid.entry_size  = sizeof(sys_ipuc_info_t);
    appid.rt_en = 1;
#else
    appid.entry_size  = sizeof(sys_wb_ipuc_info_t);
    appid.rt_en = 0;
#endif
    if (DRV_IS_DUET2(lchip))
    {/*Duet2 not support rt-sync*/
        appid.rt_en = 0;
    }
    ctc_wb_add_appid( lchip, &appid);

    appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1) ;
    appid.entry_num = p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM] +
        p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT] +
        p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM] +
        p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB] +
        p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB_SHORT] +
        p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM_PUB];
    appid.entry_size  = sizeof(sys_wb_nalpm_prefix_info_t);
    appid.rt_en = 0;
    ctc_wb_add_appid( lchip, &appid);

    appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_OFB) ;
    appid.entry_num = SYS_WB_IPUC_SUBID_OFB_NUM;
    appid.entry_size  = sizeof(sys_wb_ofb_t);
    appid.rt_en = 0;
    ctc_wb_add_appid( lchip, &appid);

    if (DRV_IS_DUET2(lchip))
    {
        appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_ALPM_MASTER) ;
        appid.entry_num = 1;
        appid.entry_size  = sizeof(sys_wb_ofb_t);
        appid.rt_en = 0;
        ctc_wb_add_appid( lchip, &appid);
    }
    else if(DRV_IS_AT(lchip))
    {
        appid.app_id = lchip << 16 | CTC_WB_APPID(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_PIVOT) ;
        appid.entry_num = DRV_TABLE_MAX_INDEX(lchip, DsNeoLpmL0Ipv4Bit32Snake_t);
        appid.entry_num += DRV_TABLE_MAX_INDEX(lchip, DsNeoLpmL0Ipv4Bit32Snake1_t);
        appid.entry_num *= ROUTE_NUM_PER_SNAKE_V4_L0;
        appid.entry_size  = sizeof(sys_wb_nalpm_pivot_info_t);
        appid.rt_en = 0;
        ctc_wb_add_appid( lchip, &appid);
    }

    return 0;

}

#define ___IPUC_COMMON___
#define ___________IPUC_OUTER_FUNCTION________________________
#define __0_IPUC_API__
/*Update ldp for nexthop ldp tunnel underlay change*/
int32
_sys_usw_ipuc_update_ldp_dsip(uint8 lchip, sys_com_ldp_update_t* p_param)
{
    ctc_list_pointer_node_t * node;
    sys_ipuc_ad_node_t * p_ad_node;
    sys_com_ldp_node_t ldp_node;
    sys_com_ldp_node_t* p_ldp_node = NULL;
    uint32 cmdr = 0;
    uint32 cmdw = 0;
    sys_ipuc_ad_spool_t temp_new_ad_node;
    sys_ipuc_ad_spool_t temp_old_ad_node;
    DsIpDa_m temp_ad;
    DsIpDa_m temp_old_ad;
    sys_l3if_ecmp_if_t ecmp_if = {0};
    uint8 loop_lchip = 0;

    SYS_IPUC_INIT_CHECK;

    if(lchip != (p_usw_ipuc_master[lchip]->master_lchip + p_usw_ipuc_master[lchip]->slave_lchip_cnt - 1))
    {
        return CTC_E_NONE;
    }
    lchip = p_usw_ipuc_master[lchip]->master_lchip;     /* ad spool use master_lchip dsipda to calculate */

    if ((0 == p_param->is_srv6) && SYS_NH_OVERLAY_NEW_MODE(lchip))
    {
        return CTC_E_NONE;
    }
    SYS_IPUC_LOCK;
    sal_memset(&temp_new_ad_node, 0, sizeof(temp_new_ad_node));
    sal_memset(&temp_old_ad_node, 0, sizeof(temp_old_ad_node));
    ldp_node.ldp = p_param->ldp;
    p_ldp_node = ctc_hash_lookup(p_usw_ipuc_master[lchip]->ldp_hash, &ldp_node);
    if (NULL == p_ldp_node)
    {
        SYS_IPUC_UNLOCK;
        return CTC_E_NONE;
    }

    cmdr = DRV_IOR(DsIp_t, DRV_ENTRY_FLAG);
    cmdw = DRV_IOW(DsIp_t, DRV_ENTRY_FLAG);
    temp_new_ad_node.param.p_ad = &temp_ad;
    temp_new_ad_node.param.lchip = lchip;

    temp_old_ad_node.param.p_ad = &temp_old_ad;
    temp_old_ad_node.param.lchip = lchip;

    CTC_LIST_POINTER_LOOP(node, &p_ldp_node->update_list)
    {
        p_ad_node = _ctc_container_of(node, sys_ipuc_ad_node_t, head);

        DRV_IOCTL(lchip, p_ad_node->ad_index, DRV_CMD_BMP_EN(cmdr, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &temp_old_ad);
        sal_memcpy(&temp_ad, &temp_old_ad, sizeof(temp_ad));
        SetDsIpDa(V, destMap_f, &temp_ad, p_param->destmap);
        if(p_param->ecmp_gid)
        {
            CTC_ERROR_RETURN_IPUC_UNLOCK(sys_usw_l3if_get_ecmp_if_info(lchip, p_param->ecmp_if_id, &ecmp_if));
            SetDsIpDa(V, destMap_f, &temp_ad, SYS_ENCODE_ECMP_DESTMAP(ecmp_if.hw_group_id));
            SetDsIpDa(V, tunnelEcmpHighBit_f, &temp_ad, ((ecmp_if.hw_group_id >> 11)&0x1));
        }

        temp_new_ad_node.ad_index = p_ad_node->ad_index;
        if(p_ad_node->ldp)
        {
            CTC_BIT_SET(temp_new_ad_node.flag, 0);
        }
        if(p_ad_node->overlay_nh)
        {
            CTC_BIT_SET(temp_new_ad_node.flag, 1);
        }
        /*Need to change the spool node hash location, because of spool node content changed*/
        ctc_spool_change(p_usw_ipuc_master[lchip]->ad_spool, (void*)&temp_old_ad_node, (void*)&temp_new_ad_node);

        /*write hw in the last step,because of ctc spool change need to read old hw info to cmp*/
        DRV_IOCTL(lchip, p_ad_node->ad_index, DRV_CMD_BMP_EN(cmdw, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &temp_ad);


        for(loop_lchip = 1; loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt; loop_lchip++)
        {
            if(p_param->ecmp_gid)
            {
                CTC_ERROR_RETURN_IPUC_UNLOCK(sys_usw_l3if_get_ecmp_if_info(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_param->ecmp_if_id, &ecmp_if));
                SetDsIpDa(V, destMap_f, &temp_ad, SYS_ENCODE_ECMP_DESTMAP(ecmp_if.hw_group_id));
                SetDsIpDa(V, tunnelEcmpHighBit_f, &temp_ad, ((ecmp_if.hw_group_id >> 11)&0x1));
            }

            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_ad_node->ad_index, DRV_CMD_BMP_EN(cmdw, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &temp_ad);
        }

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "update DsIP adIndex:%d, destmap:0x%x, ecmpGid:%d\n",
            p_ad_node->ad_index, p_param->destmap, p_param->ecmp_gid);
    }

    SYS_IPUC_UNLOCK;

    return 0;
}

int32
sys_usw_ipuc_update_ldp_dsip(uint8 lchip, sys_com_ldp_update_t* p_param)
{
    uint8 lchip_start              = 0;
    uint8 lchip_end                = 0;
    uint8 all_chip = 1;

    CTC_AT_FOREACH_LCHIP2(lchip_start, lchip_end, all_chip, CTC_FEATURE_IPUC)
    {
        _sys_usw_ipuc_update_ldp_dsip(lchip, p_param);
    }
    return CTC_E_NONE;
}

/*Update dsip for ldp id change*/
int32
_sys_usw_ipuc_update_dsip_by_nhid(uint8 lchip, sys_com_ldp_update_t* p_param)
{
    ctc_list_pointer_node_t * node;
    ctc_list_pointer_node_t * node_next;
    sys_ipuc_ad_node_t * p_ad_node;
    sys_com_ldp_node_t ldp_node;
    sys_com_ldp_node_t* p_ldp_node = NULL;
    uint32 cmdr = 0;
    uint32 cmdw = 0;
    sys_ipuc_ad_spool_t temp_new_ad_node;
    sys_ipuc_ad_spool_t temp_old_ad_node;
    DsIpDa_m temp_ad;
    DsIpDa_m temp_old_ad;
    sys_l3if_ecmp_if_t ecmp_if = {0};
    uint8 loop_lchip = 0;
	uint8 u1_type = 0;
    uint16 ecmpGroupId = 0;
    uint16 cid = 0;


    SYS_IPUC_INIT_CHECK;
    if(lchip != (p_usw_ipuc_master[lchip]->master_lchip + p_usw_ipuc_master[lchip]->slave_lchip_cnt - 1))
    {
        return CTC_E_NONE;
    }
    lchip = p_usw_ipuc_master[lchip]->master_lchip;     /* ad spool use master_lchip dsipda to calculate */

    sal_memset(&temp_new_ad_node, 0, sizeof(temp_new_ad_node));
    sal_memset(&temp_old_ad_node, 0, sizeof(temp_old_ad_node));
    SYS_IPUC_LOCK;

    ldp_node.ldp = p_param->nhid;
    p_ldp_node = ctc_hash_lookup(p_usw_ipuc_master[lchip]->nhid_hash, &ldp_node);
    if (NULL == p_ldp_node)
    {
        SYS_IPUC_UNLOCK;
        return CTC_E_NONE;
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "update dsipda, nhid %u, new ldp %u\n", p_param->nhid, p_param->ldp);
    cmdr = DRV_IOR(DsIp_t, DRV_ENTRY_FLAG);
    cmdw = DRV_IOW(DsIp_t, DRV_ENTRY_FLAG);
    temp_new_ad_node.param.p_ad = &temp_ad;
    temp_new_ad_node.param.lchip = lchip;

    temp_old_ad_node.param.p_ad = &temp_old_ad;
    temp_old_ad_node.param.lchip = lchip;
    /*write table use dsip while spool node use p_ad_node->ad*/
    CTC_LIST_POINTER_LOOP(node, &p_ldp_node->update_list)
    {
        p_ad_node = _ctc_container_of(node, sys_ipuc_ad_node_t, nhid_list_head);

        DRV_IOCTL(lchip, p_ad_node->ad_index, DRV_CMD_BMP_EN(cmdr, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &temp_old_ad);
        sal_memcpy(&temp_ad, &temp_old_ad, sizeof(temp_ad));

        u1_type = GetDsIpDa(V, u1Type_f, &temp_ad);
        if (1 == u1_type)
        {
            SetDsIpDa(V, destMap_f, &temp_ad, p_param->destmap);
            SetDsIpDa(V, tunnelEcmpHighBit_f, &temp_ad, ((p_param->ecmp_gid >> 11)&0x1));
            SetDsIpDa(V, apsBridgeEn_f, &temp_ad, p_param->aps_en);
            if (p_param->dsnh_valid)
            {
                SetDsIpDa(V, nextHopPtr_f, &temp_ad, p_param->dsnh_offset);
                SetDsIpDa(V, bypassIngressEdit_f, &temp_ad, p_param->bypass_igr_edit);
                SetDsIpDa(V, nextHopExt_f, &temp_ad, p_param->nexthop_ext);
            }
        }
        else if (2 == u1_type)
        {
            if (GetDsIpDa(V, u1_g3_ecmpTunnelMode_f, &temp_ad))
            {
                ecmpGroupId = GetDsIpDa(V, u1_g3_ecmpGroupId_f, &temp_ad);
                cid = ecmpGroupId >> 5;
                if (CTC_IS_BIT_SET(ecmpGroupId, 4))
                {
                    cid += (GetDsIpDa(V, statsPtr_f, &temp_ad) >> 12) << 7;                  
                }
                if (p_param->dsnh_valid)
                {
                    SetDsIpDa(V, u1_g3_dsFwdPtr_f, &temp_ad, p_param->dsnh_offset & 0xFFFF);    
                    SetDsIpDa(V, u1_g3_ecmpGroupId_f, &temp_ad, (cid << 5) | (1 << 4) | ((p_param->bypass_igr_edit << 3) | (p_param->nexthop_ext << 2) | ((p_param->dsnh_offset >> 16) & 0x3)));
                }
                SetDsIpDa(V, statsPtr_f, &temp_ad, ((cid >> 7) << 12) | (p_param->ecmp_gid & 0xFFF));
            }
            else if (p_param->dsnh_valid)
            {
                cid = GetDsIpDa(V, u1_g3_dsFwdPtr_f, &temp_ad);
                SetDsIpDa(V, u1_g3_dsFwdPtr_f, &temp_ad, p_param->dsnh_offset & 0xFFFF);
                SetDsIpDa(V, u1_g3_ecmpGroupId_f, &temp_ad, ((cid << 5) | (p_param->bypass_igr_edit << 3) | (p_param->nexthop_ext << 2) | ((p_param->dsnh_offset >> 16) & 0x3)));
            }
        }

        if ((2 == GetDsIpDa(V, u3Type_f, &temp_ad) || 0 == GetDsIpDa(V, u3Type_f, &temp_ad)) && (0 == p_param->is_srv6))
        {
            SetDsIpDa(V, logicPort_f, &temp_ad, p_param->ldp);
            SetDsIpDa(V, u3Type_f, &temp_ad, p_param->ldp ? 2 : 0);
        }
        
        if ((p_ad_node->ldp != p_param->ldp) || (p_param->dsnh_valid) || (0 == p_param->is_srv6))
        {
            /*remove from old ldp list  and add to new ldp list*/
            if(p_ad_node->ldp)
            {
                sys_usw_remove_ldp_node(lchip, p_usw_ipuc_master[lchip]->ldp_hash, p_ad_node->ldp, &p_ad_node->head);
            }

            temp_new_ad_node.ad_index = p_ad_node->ad_index;
            if(p_ad_node->ldp)
            {
                CTC_BIT_SET(temp_new_ad_node.flag, 0);
            }
            if(p_ad_node->overlay_nh)
            {
                CTC_BIT_SET(temp_new_ad_node.flag, 1);
            }
            temp_new_ad_node.param.ldp = p_param->ldp;
            /*add new*/
            ctc_spool_change(p_usw_ipuc_master[lchip]->ad_spool, (void*)&temp_old_ad_node, (void*)&temp_new_ad_node);
            if(p_param->ldp)
            {
                sys_usw_add_ldp_node(lchip, p_usw_ipuc_master[lchip]->ldp_hash, p_param->ldp, &p_ad_node->head);
            }
            p_ad_node->ldp = p_param->ldp;
        }
        /*write hw in the last step,because of ctc spool change need to read old hw info to cmp*/
        DRV_IOCTL(lchip, p_ad_node->ad_index, DRV_CMD_BMP_EN(cmdw, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &temp_ad);


        for(loop_lchip = 1; loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt; loop_lchip++)
        {
            if (1 == GetDsIpDa(V, u1Type_f, &temp_ad) && p_param->ecmp_gid)
            {
                CTC_ERROR_RETURN_IPUC_UNLOCK(sys_usw_l3if_get_ecmp_if_info(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_param->ecmp_if_id, &ecmp_if));
                SetDsIpDa(V, destMap_f, &temp_ad, SYS_ENCODE_ECMP_DESTMAP(ecmp_if.hw_group_id));
                SetDsIpDa(V, tunnelEcmpHighBit_f, &temp_ad, ((ecmp_if.hw_group_id >> 11)&0x1));
            }
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_ad_node->ad_index, DRV_CMD_BMP_EN(cmdw, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &temp_ad);
        }

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "update DsIP adIndex:%d, destmap:0x%x, ecmpGid:%d\n",
            p_ad_node->ad_index, p_param->destmap, p_param->ecmp_gid);
    }

    if (p_param->is_del)
    {
        CTC_LIST_POINTER_LOOP_DEL(node, node_next, &p_ldp_node->update_list)
        {
            p_ad_node = _ctc_container_of(node, sys_ipuc_ad_node_t, nhid_list_head);
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "remove l3 dsip %u from nhid %u\n", p_ad_node->ad_index, p_ad_node->overlay_nh);
            sys_usw_remove_ldp_node(lchip, p_usw_ipuc_master[lchip]->nhid_hash, p_ad_node->overlay_nh, &p_ad_node->nhid_list_head);
            p_ad_node->overlay_nh = 0;
        }
    }

    SYS_IPUC_UNLOCK;

    return 0;
}

int32
sys_usw_ipuc_update_dsip_by_nhid(uint8 lchip, sys_com_ldp_update_t* p_param)
{
    uint8 lchip_start              = 0;
    uint8 lchip_end                = 0;
    uint8 all_chip = 1;

    CTC_AT_FOREACH_LCHIP2(lchip_start, lchip_end, all_chip, CTC_FEATURE_IPUC)
    {
        _sys_usw_ipuc_update_dsip_by_nhid(lchip, p_param);
    }
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_add_tcam(uint8 lchip, sys_ipuc_param_t *p_sys_param)
{
    int32 ret = CTC_E_NONE;
    sys_ipuc_tcam_data_t tcam_data = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    tcam_data.opt_type = DO_ADD;
    tcam_data.key_type = SYS_IPUC_TCAM_FLAG_TCAM;
    tcam_data.ipuc_param = &p_sys_param->param;
    tcam_data.info = p_sys_param->info;

    ret = MCHIP_IPUC(lchip)->alloc_tcam_key_index(lchip, &tcam_data);

    if (ret)
    {
        if(CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH))
        {
            _sys_usw_ipuc_bind_nexthop(lchip, p_sys_param, 0);
        }
        return ret;
    }

    p_sys_param->info->key_index = tcam_data.key_index;

    CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->tcam_write_ad(lchip, &tcam_data), ret, error0);

    /* write ipuc tcam key entry */
    CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->tcam_write_key(lchip, &tcam_data), ret, error1);

    return CTC_E_NONE;

error1:
    tcam_data.opt_type = DO_DEL;
    MCHIP_IPUC(lchip)->tcam_write_ad(lchip, &tcam_data);

error0:
    MCHIP_IPUC(lchip)->free_tcam_key_index(lchip, &tcam_data);

    return ret;
}

int32
sys_usw_ipuc_del_tcam(uint8 lchip, sys_ipuc_param_t *p_sys_param)
{
    sys_ipuc_tcam_data_t tcam_data = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    tcam_data.opt_type = DO_DEL;
    tcam_data.key_type = SYS_IPUC_TCAM_FLAG_TCAM;
    tcam_data.key_index = p_sys_param->info->key_index;
    tcam_data.ipuc_param = &p_sys_param->param;
    tcam_data.info = p_sys_param->info;

    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->tcam_write_key(lchip, &tcam_data));

    /* TCAM do not need to build remove offset, only need to clear soft offset info */
    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->free_tcam_key_index(lchip, &tcam_data));

    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->tcam_write_ad(lchip, &tcam_data));

    return CTC_E_NONE;
}

int32
sys_usw_ipuc_update_tcam(uint8 lchip, sys_ipuc_param_t *p_sys_param)
{
    sys_ipuc_tcam_data_t tcam_data = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    tcam_data.opt_type = DO_UPDATE;
    tcam_data.key_type = SYS_IPUC_TCAM_FLAG_TCAM;
    tcam_data.ipuc_param = &p_sys_param->param;
    tcam_data.info = p_sys_param->info;
    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->tcam_write_ad(lchip, &tcam_data));

    return CTC_E_NONE;
}

int32
sys_at_ipuc_write_ipda(uint8 lchip, void* p_v_sys_param, uint8 by_user, void* p_v_nhinfo)
{
    /* DsIp_m and ds_ipv4_ucast_da_tcam_t are the same*/
    uint32 cmd = 0;
    DsIpDa_m dsipda;
    uint32 field_value = 0;
    uint32 fwd_offset;
    uint32 stats_ptr = 0;
    sys_ipuc_param_t* p_sys_param = (sys_ipuc_param_t*)p_v_sys_param;
    sys_nh_info_dsnh_t* p_nhinfo = (sys_nh_info_dsnh_t*)p_v_nhinfo;
    uint32 route_flag = p_sys_param->info->route_flag;
    sys_ipuc_info_t* p_ipuc_info = p_sys_param->info;
    ctc_ipuc_param_t* p_ctc_param = &p_sys_param->param;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&dsipda, 0, sizeof(dsipda));


    if (p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY && p_nhinfo->logic_port)
    {
        p_sys_param->ldp = p_nhinfo->logic_port;
    }
    else if (p_nhinfo->nh_entry_type == SYS_NH_TYPE_SRV6)
    {
        p_sys_param->ldp = SYS_COM_LDP_SRH_ID(p_nhinfo->tunnel_id);
    }

    if ((p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY) || (p_nhinfo->nh_entry_type == SYS_NH_TYPE_SRV6))
    {
         p_sys_param->overlay_nhid = p_ctc_param->nh_id;
    }

    if (p_sys_param->param.fid)
    {
        SetDsIpDa(V, u3Type_f, &dsipda, 3);
        SetDsIpDa(V, fidValid_f, &dsipda, 1);
        SetDsIpDa(V, fid_f, &dsipda, p_sys_param->param.fid & 0x7fff);
    }
    else 
    {
        if (p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY && p_nhinfo->logic_port)
        {
            SetDsIpDa(V, u3Type_f, &dsipda, 2);
            SetDsIpDa(V, logicPort_f, &dsipda, p_nhinfo->logic_port);
        }
        else if (p_ctc_param->cid)
        {
            SetDsIpDa(V, u3Type_f, &dsipda, 1);
            SetDsIpDa(V, u3_g2_categoryId_f, &dsipda, p_sys_param->param.cid);
        }
    }

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_TTL_CHECK);
    SetDsIpDa(V, ttlCheckEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_PROTOCOL_ENTRY);
    SetDsIpDa(V, exception3CtlEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_SELF_ADDRESS);
    SetDsIpDa(V, bfdEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_CHECK);
    SetDsIpDa(V, icmpCheckEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_ERR_MSG_CHECK);
    SetDsIpDa(V, icmpErrMsgCheckEn_f, &dsipda, field_value);
    
    if(!p_sys_param->param.masklen)
    {
        if (by_user)
        {
            field_value = 1;
            SetDsIpDa(V, isDefaultRoute_f, &dsipda, field_value);
            field_value = 0;
            SetDsIpDa(V, isCtcDefaultRoute_f, &dsipda, field_value);
        }
        else
        {
            field_value = 1;
            SetDsIpDa(V, isDefaultRoute_f, &dsipda, field_value);
            field_value = p_usw_ipuc_master[lchip]->rpf_permit_default_en ? 0 : 1;
            SetDsIpDa(V, isCtcDefaultRoute_f, &dsipda, field_value);
        }
    }
    
    if (p_ctc_param->new_l4_dst_port)
    {
        SetDsIpDa(V, dnatL4DstPort_f, &dsipda, p_ctc_param->new_l4_dst_port);
        SetDsIpDa(V, u2Type_f, &dsipda, 3);
    }
    else if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_RPF_CHECK) || CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_CHECK))
    {
        field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_RPF_CHECK);
        SetDsIpDa(V, rpfCheckEn_f, &dsipda, field_value);
        field_value = p_ipuc_info->rpf_id;
        SetDsIpDa(V, rpfIfId_f, &dsipda, field_value);
        field_value = 0;
        SetDsIpDa(V, u2Type_f, &dsipda, field_value);
        field_value = p_ipuc_info->rpf_mode;
        SetDsIpDa(V, rpfCheckMode_f, &dsipda, field_value);
    }

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CANCEL_NAT);
    SetDsIpDa(V, l3IfType_f, &dsipda, field_value);  /* 0- external,1- internal */

    field_value = (p_ctc_param->route_data << 2);/* use dsipda.exceptionSubIndex as selfdeftype*/
    if(CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CPU))
    {
        field_value = field_value | 0x3;  /* use IpeRouteCtl_gExcepSubIndex_3 as real ipda exceptionSubIndex, 0 is invalid*/
    }
     SetDsIpDa(V, exceptionSubIndex_f, &dsipda, field_value);

    if ((p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY && SYS_NH_OVERLAY_NEW_MODE(lchip)) || ((p_nhinfo->nh_entry_type == SYS_NH_TYPE_SRV6) && DRV_FROM_AT(lchip) && p_nhinfo->is_ecmp_intf))
    {
        /*
                FooDsIp.nextHopPtr(17,0) = (DsIp.u1.g3.ecmpGroupId(1,0),DsIp.u1.g3.dsFwdPtr(15,0));
                FooDsIp.nextHopExt = DsIp.u1.g3.ecmpGroupId(2);
                FooDsIp.bypassIngressEdit = DsIp.u1.g3.ecmpGroupId(3);
                */
        SetDsIpDa(V, u1_g3_ecmpTunnelMode_f, &dsipda, 1);
        SetDsIpDa(V, u1_g3_dsFwdPtr_f, &dsipda, p_nhinfo->dsnh_offset & 0xFFFF);

        if (p_nhinfo->is_ecmp_intf)
        {
            CTC_MAX_VALUE_CHECK(p_ctc_param->cid, 0x7FF);
            if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
            {
                return CTC_E_PARAM_CONFLICT;
            }
            SetDsIpDa(V, u1_g3_ecmpGroupId_f, &dsipda,(p_ctc_param->cid << 5) | (1<<4) |((p_nhinfo->bypass_igr_edit << 3) | (p_nhinfo->nexthop_ext << 2) | ((p_nhinfo->dsnh_offset >> 16) & 0x3)));
            SetDsIpDa(V, statsPtr_f, &dsipda, ((p_ctc_param->cid >> 7) << 12) | (p_nhinfo->ecmp_group_id & 0xFFF));
        }
        else
        {
            CTC_MAX_VALUE_CHECK(p_ctc_param->cid, 0x7F);
            SetDsIpDa(V, u1_g3_ecmpGroupId_f, &dsipda, ((p_ctc_param->cid << 5) | (p_nhinfo->bypass_igr_edit << 3) | (p_nhinfo->nexthop_ext << 2) | ((p_nhinfo->dsnh_offset >> 16) & 0x3)));
            if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
            {
                CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, p_ctc_param->stats_id, &stats_ptr));
                SetDsIpDa(V, statsPtr_f, &dsipda, stats_ptr);
            }
        }
        SetDsIpDa(V, u1_g3_priorityPathEn_f, &dsipda, 1);
        SetDsIpDa(V, u1Type_f, &dsipda, 2);

        if (p_sys_param->param.fid && p_nhinfo->logic_port)
        {
            SetDsIpDa(V, u2Type_f, &dsipda, 0);
            SetDsIpDa(V, rpfIfId_f, &dsipda, p_nhinfo->logic_port);
        }
    }
    else if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_MERGE_KEY))
    {
        CTC_ERROR_RETURN(_sys_usw_ipuc_build_ipda_nexthop(lchip, p_sys_param, p_nhinfo, &dsipda));
    }
    else
    {
        if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
        {
            CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, p_ctc_param->stats_id, &stats_ptr));
            SetDsIpDa(V, statsPtr_f, &dsipda, stats_ptr);
        }

        if (p_nhinfo->ecmp_valid)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Ecmp number is %d\r\n", p_nhinfo->ecmp_cnt);
            SetDsIpDa(V, u1Type_f, &dsipda, 2);
            field_value = p_nhinfo->ecmp_group_id & 0xFFF;
            SetDsIpDa(V, u1_g3_ecmpGroupId_f, &dsipda, field_value);
            SetDsIpDa(V, hEcmpEnable_f, &dsipda, p_nhinfo->h_ecmp_en);
            if (p_ctc_param->cid)
            {
                SetDsIpDa(V, u1_g3_priorityPathEn_f, &dsipda, 1);    /*use u1_g3_priorityPathEn_f as tunnelEcmpNewMode per DSIP entry */
                SetDsIpDa(V, u1_g3_dsFwdPtr_f, &dsipda, p_sys_param->param.cid);   /*use u1_g3_dsFwdPtr_f as cid */
            }
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_dsfwd_offset(lchip, p_ctc_param->nh_id, &fwd_offset, 0, CTC_FEATURE_IPUC));
            field_value = fwd_offset & 0xFFFF;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC: old ad index = %d, dsfwd ptr = 0x%x\n",
                             p_ipuc_info->ad_index, field_value);
            if ((p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY || p_sys_param->param.fid) && (p_ctc_param->cid))
            {
                SetDsIpDa(V, u1_g4_dsFwdPtr_f, &dsipda, field_value);
                SetDsIpDa(V, u1Type_f, &dsipda, 3);
                SetDsIpDa(V, categoryId_f, &dsipda, p_sys_param->param.cid);
                if (p_nhinfo->is_ecmp_intf)
                {
                    SetDsIpDa(V, u1_g4_ecmpTunnelMode_f, &dsipda, 1);
                    SetDsIpDa(V, u1_g4_ecmpGroupId_f, &dsipda, p_nhinfo->ecmp_group_id & 0xFFF);
                }
                if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
                {
                    return CTC_E_NOT_SUPPORT;
                }
            }
            else
            {
                SetDsIpDa(V, u1_g3_dsFwdPtr_f, &dsipda, field_value);
                SetDsIpDa(V, u1Type_f, &dsipda, 2);
                if (p_nhinfo->is_ecmp_intf)
                {
                    SetDsIpDa(V, u1_g3_ecmpTunnelMode_f, &dsipda, 1);
                    SetDsIpDa(V, u1_g3_ecmpGroupId_f, &dsipda, p_nhinfo->ecmp_group_id & 0xFFF);
                }
                if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
                {
                    CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, p_ctc_param->stats_id, &stats_ptr));
                    SetDsIpDa(V, statsPtr_f, &dsipda, stats_ptr);
                }
            }
        }
    }

    if(CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_XDATA))
    {
        sys_ipuc_xdata_info_t xdata_info;
        sal_memset(&xdata_info, 0, sizeof(xdata_info));
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "proccess Xdata......\n");

        GetDsIpDa(A, xAdData_f, &dsipda, xdata_info.ds_value);
        CTC_ERROR_RETURN(_sys_usw_ipuc_get_xdata_withcheck(lchip, p_sys_param->xdata, &xdata_info, &dsipda, 1));

        if(CTC_IS_BIT_SET(xdata_info.flag, SYS_IPUC_XDATA_U2G1))
        {
            SetDsIpDa(V, u2_g1_xAdDataValid_f, &dsipda, 1);  /*u2_g1_xAdDataValid*/
        }

        SetDsIpDa(A, xAdData_f, &dsipda, xdata_info.ds_value);
        SetDsIpDa(V, xAdEn_f, &dsipda, 1);
    }
    
    if (lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        /* no need alloc ad_index */
    }
    else if (!CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
        /* _sys_usw_ipuc_add_ad_profile param 3 is always 0 beacause we remove old dsipda in update ending func */
        CTC_ERROR_RETURN(_sys_usw_ipuc_add_ad_profile(lchip, p_sys_param, (void*)&dsipda, 0));
    }
    else if(p_usw_ipuc_master[lchip]->default_route_mode)
    {
        field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_IS_IPV6) ? CTC_IP_VER_6 : CTC_IP_VER_4;
        p_ipuc_info->ad_index = p_usw_ipuc_master[lchip]->default_base[field_value] + p_ipuc_info->vrf_id;
    }

    
    if (!p_sys_param->dsipda_built)
    {
        cmd = DRV_IOW(DsIp_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);
        if(lchip == p_usw_ipuc_master[lchip]->master_lchip)
        {
            sys_nh_info_dsnh_t nhinfo;
            for(loop_lchip = 1; loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt; loop_lchip++)
            {
                sal_memset(&nhinfo, 0, sizeof(sys_nh_info_dsnh_t));
                CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param->param.nh_id, &nhinfo, 0));
                CTC_ERROR_RETURN(sys_at_ipuc_write_ipda(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param, by_user, &nhinfo));
            }
        }
    }

    return CTC_E_NONE;
}

int32
sys_tmm_ipuc_write_ipda(uint8 lchip, void* p_v_sys_param, uint8 by_user, void* p_v_nhinfo)
{
    /* DsIp_m and ds_ipv4_ucast_da_tcam_t are the same*/
    uint32 cmd = 0;
    DsIpDa_m dsipda;
    uint32 field_value = 0;
    uint32 fwd_offset;
    uint32 stats_ptr = 0;
    sys_ipuc_param_t* p_sys_param = (sys_ipuc_param_t*)p_v_sys_param;
    sys_nh_info_dsnh_t* p_nhinfo = (sys_nh_info_dsnh_t*)p_v_nhinfo;
    uint32 route_flag = p_sys_param->info->route_flag;
    sys_ipuc_info_t* p_ipuc_info = p_sys_param->info;
    ctc_ipuc_param_t* p_ctc_param = &p_sys_param->param;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&dsipda, 0, sizeof(dsipda));

    if (p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY && p_nhinfo->logic_port)
    {
        p_sys_param->ldp = p_nhinfo->logic_port;
    }
    else if (p_nhinfo->nh_entry_type == SYS_NH_TYPE_SRV6)
    {
        p_sys_param->ldp = SYS_COM_LDP_SRH_ID(p_nhinfo->tunnel_id);
    }

    if ((p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY) || (p_nhinfo->nh_entry_type == SYS_NH_TYPE_SRV6))
    {
         p_sys_param->overlay_nhid = p_ctc_param->nh_id;
    }
    if (p_sys_param->param.fid)
    {
        SetDsIpDa(V, u3Type_f, &dsipda, 3);
        SetDsIpDa(V, fidValid_f, &dsipda, 1);
        SetDsIpDa(V, fid_f, &dsipda, p_sys_param->param.fid & 0x7fff);
    }
    else
    {
        if (p_ctc_param->cid)
        {
            SetDsIpDa(V, u3Type_f, &dsipda, 1);
            SetDsIpDa(V, u3_g2_categoryId_f, &dsipda, p_sys_param->param.cid);
        }
        else if (p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY && p_nhinfo->logic_port)
        {
            SetDsIpDa(V, u3Type_f, &dsipda, 2);
            SetDsIpDa(V, logicPort_f, &dsipda, p_nhinfo->logic_port);
        }
    }

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_TTL_CHECK);
    SetDsIpDa(V, ttlCheckEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_PROTOCOL_ENTRY);
    SetDsIpDa(V, exception3CtlEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_SELF_ADDRESS);
    SetDsIpDa(V, bfdEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_CHECK);
    SetDsIpDa(V, icmpCheckEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_ERR_MSG_CHECK);
    SetDsIpDa(V, icmpErrMsgCheckEn_f, &dsipda, field_value);

    if(!p_sys_param->param.masklen)
    {
        if (by_user)
        {
            field_value = 1;
            SetDsIpDa(V, isDefaultRoute_f, &dsipda, field_value);
            field_value = 0;
            SetDsIpDa(V, isCtcDefaultRoute_f, &dsipda, field_value);
        }
        else
        {
            field_value = 1;
            SetDsIpDa(V, isDefaultRoute_f, &dsipda, field_value);
            field_value = p_usw_ipuc_master[lchip]->rpf_permit_default_en ? 0 : 1;
            SetDsIpDa(V, isCtcDefaultRoute_f, &dsipda, field_value);
        }
    }

    if (p_ctc_param->new_l4_dst_port)
    {
        SetDsIpDa(V, dnatL4DstPort_f, &dsipda, p_ctc_param->new_l4_dst_port);
        SetDsIpDa(V, u2Type_f, &dsipda, 3);
    }
    else if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_RPF_CHECK) || CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_CHECK))
    {
        field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_RPF_CHECK);
        SetDsIpDa(V, rpfCheckEn_f, &dsipda, field_value);
        field_value = p_ipuc_info->rpf_id;
        SetDsIpDa(V, rpfIfId_f, &dsipda, field_value);
        field_value = 0;
        SetDsIpDa(V, u2Type_f, &dsipda, field_value);
        field_value = p_ipuc_info->rpf_mode;
        SetDsIpDa(V, rpfCheckMode_f, &dsipda, field_value);
    }

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CANCEL_NAT);
    SetDsIpDa(V, l3IfType_f, &dsipda, field_value);  /* 0- external,1- internal */

    field_value = (p_ctc_param->route_data << 2);/* use dsipda.exceptionSubIndex as selfdeftype*/
    if(CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CPU))
    {
        field_value = field_value | 0x3;  /* use IpeRouteCtl_gExcepSubIndex_3 as real ipda exceptionSubIndex, 0 is invalid*/
    }
     SetDsIpDa(V, exceptionSubIndex_f, &dsipda, field_value);

    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_MERGE_KEY))
    {
        CTC_ERROR_RETURN(_sys_usw_ipuc_build_ipda_nexthop(lchip, p_sys_param, p_nhinfo, &dsipda));
    }
    else
    {
        if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
        {
            CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, p_ctc_param->stats_id, &stats_ptr));
            SetDsIpDa(V, statsPtr_f, &dsipda, stats_ptr);
        }

        if (p_nhinfo->ecmp_valid)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Ecmp number is %d\r\n", p_nhinfo->ecmp_cnt);
            SetDsIpDa(V, u1Type_f, &dsipda, 2);
            field_value = p_nhinfo->ecmp_group_id & 0xFFF;
            SetDsIpDa(V, u1_g3_ecmpGroupId_f, &dsipda, field_value);
            SetDsIpDa(V, hEcmpEnable_f, &dsipda, p_nhinfo->h_ecmp_en);
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_dsfwd_offset(lchip, p_ctc_param->nh_id, &fwd_offset, 0, CTC_FEATURE_IPUC));
            field_value = fwd_offset & 0xFFFF;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC: old ad index = %d, dsfwd ptr = 0x%x\n",
                             p_ipuc_info->ad_index, field_value);
            if ((p_nhinfo->nh_entry_type == SYS_NH_TYPE_OVERLAY || p_sys_param->param.fid) && (p_ctc_param->cid))
            {
                SetDsIpDa(V, u1_g4_dsFwdPtr_f, &dsipda, field_value);
                SetDsIpDa(V, u1Type_f, &dsipda, 3);
                SetDsIpDa(V, categoryId_f, &dsipda, p_sys_param->param.cid);
                if (p_nhinfo->is_ecmp_intf)
                {
                    SetDsIpDa(V, u1_g4_ecmpTunnelMode_f, &dsipda, 1);
                    SetDsIpDa(V, u1_g4_ecmpGroupId_f, &dsipda, p_nhinfo->ecmp_group_id & 0xFFF);
                }
                if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
                {
                    return CTC_E_NOT_SUPPORT;
                }
            }
            else
            {
                SetDsIpDa(V, u1_g3_dsFwdPtr_f, &dsipda, field_value);
                SetDsIpDa(V, u1Type_f, &dsipda, 2);
                if (p_nhinfo->is_ecmp_intf)
                {
                    SetDsIpDa(V, u1_g3_ecmpTunnelMode_f, &dsipda, 1);
                    SetDsIpDa(V, u1_g3_ecmpGroupId_f, &dsipda, p_nhinfo->ecmp_group_id & 0xFFF);
                }
                if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
                {
                    CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, p_ctc_param->stats_id, &stats_ptr));
                    SetDsIpDa(V, statsPtr_f, &dsipda, stats_ptr);
                }
            }
        }
    }

    if (lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        /* no need alloc ad_index */
    }
    else if (!CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
        /* _sys_usw_ipuc_add_ad_profile param 3 is always 0 beacause we remove old dsipda in update ending func */
        CTC_ERROR_RETURN(_sys_usw_ipuc_add_ad_profile(lchip, p_sys_param, (void*)&dsipda, 0));
    }
    else if(p_usw_ipuc_master[lchip]->default_route_mode)
    {
        field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_IS_IPV6) ? CTC_IP_VER_6 : CTC_IP_VER_4;
        p_ipuc_info->ad_index = p_usw_ipuc_master[lchip]->default_base[field_value] + p_ipuc_info->vrf_id;
    }

    if(!p_sys_param->dsipda_built)
    {
        cmd = DRV_IOW(DsIp_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);
        if(lchip == p_usw_ipuc_master[lchip]->master_lchip)
        {
            sys_nh_info_dsnh_t nhinfo;
            for(loop_lchip = 1; loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt; loop_lchip++)
            {
                sal_memset(&nhinfo, 0, sizeof(sys_nh_info_dsnh_t));
                CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param->param.nh_id, &nhinfo, 0));
                CTC_ERROR_RETURN(sys_tmm_ipuc_write_ipda(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param, by_user, &nhinfo));
            }
        }
    }


    return CTC_E_NONE;
}

int32
sys_duet2_ipuc_write_ipda(uint8 lchip, void* p_v_sys_param, uint8 by_user, void* p_v_nhinfo)
{
    /* DsIp_m and ds_ipv4_ucast_da_tcam_t are the same*/
    uint32 cmd = 0;
    DsIpDa_m dsipda;
    uint32 field_value = 0;
    uint32 fwd_offset;
    uint32 stats_ptr = 0;
    sys_ipuc_param_t* p_sys_param = (sys_ipuc_param_t*)p_v_sys_param;
    sys_nh_info_dsnh_t* p_nhinfo = (sys_nh_info_dsnh_t*)p_v_nhinfo;
    uint32 route_flag = p_sys_param->info->route_flag;
    sys_ipuc_info_t* p_ipuc_info = p_sys_param->info;
    ctc_ipuc_param_t* p_ctc_param = &p_sys_param->param;
    sys_nh_info_dsnh_t nh_info;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&dsipda, 0, sizeof(dsipda));

    if(DRV_IS_TSINGMA(lchip))
    {
        sal_memset(&nh_info, 0, sizeof(nh_info));
        CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, p_ctc_param->nh_id, &nh_info, 0));
        if ((nh_info.bind_ldp) && nh_info.logic_port)
        {
            p_sys_param->ldp = nh_info.logic_port;
        }
    }
    if (p_ctc_param->cid)
    {
        SetDsIpDa(V, categoryIdValid_f, &dsipda, 1);
        SetDsIpDa(V, categoryId_f, &dsipda, p_sys_param->param.cid);
    }
    else
    {
        //TODO SetDsIpDa(V, categoryIdOrServiceId_f, &dsipda, p_sys_param->param.cid);
    }

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_TTL_CHECK);
    SetDsIpDa(V, ttlCheckEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_PROTOCOL_ENTRY);
    SetDsIpDa(V, exception3CtlEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_SELF_ADDRESS);
    SetDsIpDa(V, selfAddress_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_CHECK);
    SetDsIpDa(V, icmpCheckEn_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_ICMP_ERR_MSG_CHECK);
    SetDsIpDa(V, icmpErrMsgCheckEn_f, &dsipda, field_value);

    if (!p_sys_param->param.masklen)
    {
        if (DRV_IS_DUET2(lchip))
        {
            field_value = 1;
            SetDsIpDa(V, isDefaultRoute_f, &dsipda, field_value);
        }
        else
        {
            if (by_user)
            {
                field_value = 1;
                SetDsIpDa(V, isDefaultRoute_f, &dsipda, field_value);
                field_value = 0;
                SetDsIpDa(V, isCtcDefaultRoute_f, &dsipda, field_value);
            }
            else
            {
                field_value = 1;
                SetDsIpDa(V, isDefaultRoute_f, &dsipda, field_value);
                field_value = p_usw_ipuc_master[lchip]->rpf_permit_default_en ? 0 : 1;
                SetDsIpDa(V, isCtcDefaultRoute_f, &dsipda, field_value);
            }
        }
    }
    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_RPF_CHECK);
    SetDsIpDa(V, rpfCheckEn_f, &dsipda, field_value);
    field_value = p_ipuc_info->rpf_id;
    SetDsIpDa(V, rpfIfId_f, &dsipda, field_value);

    field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CANCEL_NAT);
    SetDsIpDa(V, l3IfType_f, &dsipda, field_value);  /* 0- external,1- internal */

    field_value = p_ipuc_info->rpf_mode;
    SetDsIpDa(V, rpfCheckMode_f, &dsipda, field_value);

    if (p_nhinfo->is_ivi)
    {
        SetDsIpDa(V, iviEnable_f, &dsipda, 1);  /* ivi enable */
        SetDsIpDa(V, ptEnable_f, &dsipda, 1);   /* need do ipv4-ipv6 address translate */
    }

    if(CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CPU))
    {
        if (DRV_IS_DUET2(lchip))
        {
            /*to CPU must be equal to 63(get the low 5bits is 31), refer to sys_usw_pdu.h:SYS_L3PDU_PER_L3IF_ACTION_INDEX_RSV_IPDA_TO_CPU*/
            field_value = CTC_L3PDU_ACTION_INDEX_IPDA & 0x1F;
        }
        else
        {
            field_value = CTC_L3PDU_ACTION_INDEX_IPDA;
        }
        SetDsIpDa(V, exceptionSubIndex_f, &dsipda, field_value);
    }
    if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_MERGE_KEY))
    {
        CTC_ERROR_RETURN(_sys_usw_ipuc_build_ipda_nexthop(lchip, p_sys_param, p_nhinfo, &dsipda));
    }
    else
    {
        if (p_sys_param->param.fid)
        {
            SetDsIpDa(V, fidValid_f, &dsipda, 1);
            SetDsIpDa(V, ecmpTunnelMode_f, &dsipda, 1);
            SetDsIpDa(V, priorityPathEn_f, &dsipda, (p_sys_param->param.fid&0x1));        /*fid bit0*/
            SetDsIpDa(V, isatapCheckEn_f, &dsipda, ((p_sys_param->param.fid >> 1)&0x1));    /*fid bit1*/
            SetDsIpDa(V, ptEnable_f, &dsipda, ((p_sys_param->param.fid >> 2)&0x1));         /*fid bit2*/
            SetDsIpDa(V, ecmpGroupIdHighBits_f, &dsipda, ((p_sys_param->param.fid >> 3)&0x7f));             /*fid bit3~bit9*/
            if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_CPU))
            {
                SetDsIpDa(V, exceptionSubIndex_f, &dsipda, ((((p_sys_param->param.fid >> 10)&0xf) << 2) | (CTC_L3PDU_ACTION_INDEX_IPDA & 0x3)));         /* fid bit10~bit13 | subindex bit0~bit1 */
            }
            else
            {
                SetDsIpDa(V, exceptionSubIndex_f, &dsipda, (((p_sys_param->param.fid >> 10)&0xf) << 2));         /* fid bit10~bit13 */
            }
        }

        if (p_nhinfo->ecmp_valid)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Ecmp number is %d\r\n", p_nhinfo->ecmp_cnt);
            SetDsIpDa(V, ecmpEn_f, &dsipda, 1);
            field_value = p_nhinfo->ecmp_group_id & 0x3FF;       /* ecmp group id 10bit */
            SetDsIpDa(V, dsFwdPtrOrEcmpGroupId_f, &dsipda, field_value);

            SetDsIpDa(V, hEcmpEnable_f, &dsipda, p_nhinfo->h_ecmp_en);
        }
        else
        {
            CTC_ERROR_RETURN(sys_usw_nh_get_dsfwd_offset(lchip, p_ctc_param->nh_id, &fwd_offset, 0, CTC_FEATURE_IPUC));
            field_value = fwd_offset & 0xFFFF;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC: old ad index = %d, dsfwd ptr = 0x%x\n",
                             p_ipuc_info->ad_index, field_value);
            SetDsIpDa(V, dsFwdPtrOrEcmpGroupId_f, &dsipda, field_value);

            SetDsIpDa(V, ecmpEn_f, &dsipda, 0);

            if (p_nhinfo->is_ecmp_intf)
            {
                SetDsIpDa(V, ecmpGroupIdHighBits_f, &dsipda, (p_nhinfo->ecmp_group_id >> 3)&0x7F);
                SetDsIpDa(V, ptEnable_f, &dsipda, (p_nhinfo->ecmp_group_id >> 2)&0x1);
                SetDsIpDa(V, isatapCheckEn_f, &dsipda, (p_nhinfo->ecmp_group_id >> 1)&0x1);
                SetDsIpDa(V, priorityPathEn_f, &dsipda, p_nhinfo->ecmp_group_id && 0x1);
                SetDsIpDa(V, ecmpTunnelMode_f, &dsipda, 1);
            }
        }
        if (CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_STATS_EN))
        {
            CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip, p_ctc_param->stats_id, &stats_ptr));
            SetDsIpDa(V, tunnelGreOption_f, &dsipda, stats_ptr&0x7);
            SetDsIpDa(V, tunnelPacketType_f, &dsipda, (stats_ptr >> 3)&0x7);
            SetDsIpDa(V, tunnelPayloadOffset_f, &dsipda, (stats_ptr >> 6)&0xF);
            SetDsIpDa(V, payloadOffsetType_f, &dsipda, (stats_ptr >> 10)&0x1);
            SetDsIpDa(V, payloadSelect_f, &dsipda, (stats_ptr >> 11)&0x3);
            if (DRV_IS_DUET2(lchip))
            {
                SetDsIpDa(V, statsPtrHighBits_f, &dsipda, (stats_ptr >> 13)&0x3);
            }
            else
            {
                SetDsIpDa(V, statsPtrHighBits_f, &dsipda, (stats_ptr >> 13)&0x7);
            }
            SetDsIpDa(V, statsOrDecapSel_f, &dsipda, 1);
        }
    }

    if (lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        /* no need alloc ad_index */
    }
    else if (!CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
        /* _sys_usw_ipuc_add_ad_profile param 3 is always 0 beacause we remove old dsipda in update ending func */
        CTC_ERROR_RETURN(_sys_usw_ipuc_add_ad_profile(lchip, p_sys_param, (void*)&dsipda, 0));
    }
    else if(p_usw_ipuc_master[lchip]->default_route_mode)
    {
        field_value = CTC_FLAG_ISSET(route_flag, SYS_IPUC_FLAG_IS_IPV6) ? CTC_IP_VER_6 : CTC_IP_VER_4;
        p_ipuc_info->ad_index = p_usw_ipuc_master[lchip]->default_base[field_value] + p_ipuc_info->vrf_id;
    }

    if(!p_sys_param->dsipda_built)
    {
        cmd = DRV_IOW(DsIpDa_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);
        if(lchip == p_usw_ipuc_master[lchip]->master_lchip)
        {
            sys_nh_info_dsnh_t nhinfo;
            for(loop_lchip = 1; loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt; loop_lchip++)
            {
                sal_memset(&nhinfo, 0, sizeof(sys_nh_info_dsnh_t));
                CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param->param.nh_id, &nhinfo, 0));
                CTC_ERROR_RETURN(sys_duet2_ipuc_write_ipda(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_sys_param, by_user, &nhinfo));
            }
        }
    }

    return CTC_E_NONE;

}

int32
sys_tmm_ipuc_build_ipda_nexthop(uint8 lchip, void* p_v_sys_param, void* temp_dsnh_info, void* p_v_dsipda)
{
    uint8   gchip_id    = 0;
    uint16  lport       = 0;
    uint32  dest_id     = 0;
    uint32 dsnh_offset = 0;
    sys_ipuc_param_t* p_sys_param = (sys_ipuc_param_t*)p_v_sys_param;
    DsIpDa_m* p_dsipda = (DsIpDa_m*)p_v_dsipda;
    sys_nh_info_dsnh_t* p_dsnh_info = temp_dsnh_info;

    dsnh_offset = (DRV_FROM_AT(lchip) && p_dsnh_info->nhid == 1 && CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_SELF_ADDRESS))?0:p_dsnh_info->dsnh_offset;

    if (CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_ASSIGN_PORT))
    {
        gchip_id = CTC_MAP_GPORT_TO_GCHIP(p_sys_param->param.gport);
        lport = SYS_MAP_CTC_GPORT_TO_DRV_LPORT(p_sys_param->param.gport);
        dest_id = SYS_ENCODE_DESTMAP(gchip_id, lport);
    }
    else
    {
        dest_id = p_dsnh_info->dest_map;
    }
    SetDsIpDa(V, apsBridgeEn_f, p_dsipda, p_dsnh_info->aps_en);
    SetDsIpDa(V, destMap_f, p_dsipda, dest_id);
    SetDsIpDa(V, nextHopPtr_f, p_dsipda, dsnh_offset);
    SetDsIpDa(V, bypassIngressEdit_f, p_dsipda, p_dsnh_info->bypass_igr_edit);
    SetDsIpDa(V, nextHopExt_f, p_dsipda, p_dsnh_info->nexthop_ext);
    SetDsIpDa(V, u1Type_f, p_dsipda, 1);
    SetDsIpDa(V, tunnelEcmpHighBit_f, p_dsipda, ((p_dsnh_info->ecmp_group_id>>11)&0x1));

    if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH)
    {
        SetDsIpDa(V, macDaLowBits_f, p_dsipda, p_dsnh_info->cloud_sec_en << 3);
        SetDsIpDa(V, nextHopSaveEn_f, p_dsipda, 0);
    }
    else if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH_ROUTE0)
    {
        SetDsIpDa(V, macDaLowBits_f, p_dsipda, ((p_sys_param->param.mac[5]&0x3) | (p_dsnh_info->cloud_sec_en << 3)));
        SetDsIpDa(V, nextHopSaveEn_f, p_dsipda, 1);
    }
    else if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH_ROUTE1)
    {
        SetDsIpDa(V, macDaLowBits_f, p_dsipda, ((p_sys_param->param.mac[5]&0x7) | (p_dsnh_info->cloud_sec_en << 3)));
        SetDsIpDa(V, nextHopSaveEn_f, p_dsipda, 1);
    }
    else if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH_ROUTE2 && !p_dsnh_info->cloud_sec_en)
    {
        SetDsIpDa(V, macDaLowBits_f, p_dsipda, (p_sys_param->param.mac[5]&0xf));
        SetDsIpDa(V, nextHopSaveEn_f, p_dsipda, 1);
    }
    return CTC_E_NONE;
}

int32
sys_duet2_ipuc_build_ipda_nexthop(uint8 lchip, void* p_v_sys_param, void* temp_dsnh_info, void* p_v_dsipda)
{
    uint8   gchip_id    = 0;
    uint16  lport       = 0;
    uint32  dest_id     = 0;
    uint32 dsnh_offset = 0;
    uint8 adjust_len_idx = 0;
    sys_ipuc_param_t* p_sys_param = (sys_ipuc_param_t*)p_v_sys_param;
    DsIpDa_m* p_dsipda = (DsIpDa_m*)p_v_dsipda;
    sys_nh_info_dsnh_t* p_dsnh_info = temp_dsnh_info;

    dsnh_offset = p_dsnh_info->dsnh_offset;

    if (CTC_FLAG_ISSET(p_sys_param->info->route_flag, SYS_IPUC_FLAG_ASSIGN_PORT))
    {
        gchip_id = CTC_MAP_GPORT_TO_GCHIP(p_sys_param->param.gport);
        lport = SYS_MAP_CTC_GPORT_TO_DRV_LPORT(p_sys_param->param.gport);
        dest_id = SYS_ENCODE_DESTMAP(gchip_id, lport);
    }
    else
    {
        dest_id = p_dsnh_info->dest_map;
    }
    SetDsIpDa(V, adApsBridgeEn_f, p_dsipda, p_dsnh_info->aps_en);
    SetDsIpDa(V, adDestMap_f, p_dsipda, dest_id);
    SetDsIpDa(V, adNextHopPtr_f, p_dsipda, dsnh_offset);
    if (p_dsnh_info->bypass_igr_edit)
    {
        SetDsIpDa(V, adNextHopPtr_f, p_dsipda, dsnh_offset | SYS_NH_DSNH_BY_PASS_FLAG);
    }
    SetDsIpDa(V, adNextHopExt_f, p_dsipda, p_dsnh_info->nexthop_ext);
    if(0 != p_dsnh_info->adjust_len)
    {
        sys_usw_lkup_adjust_len_index(lchip, p_dsnh_info->adjust_len, &adjust_len_idx);
        SetDsIpDa(V, adLengthAdjustType_f, p_dsipda, adjust_len_idx);
    }
    else
    {
        SetDsIpDa(V, adLengthAdjustType_f, p_dsipda, 0);
    }
    SetDsIpDa(V, nextHopPtrValid_f, p_dsipda, 1);
    if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH)
    {
        SetDsIpDa(V, adMacDaLowBits_f, p_dsipda, p_dsnh_info->cloud_sec_en << 3);
        SetDsIpDa(V, adNextHopSaveEn_f, p_dsipda, 0);
    }
    else if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH_ROUTE0)
    {
        SetDsIpDa(V, adMacDaLowBits_f, p_dsipda, ((p_sys_param->param.mac[5]&0x3) | (p_dsnh_info->cloud_sec_en << 3)));
        SetDsIpDa(V, adNextHopSaveEn_f, p_dsipda, 1);
    }
    else if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH_ROUTE1)
    {
        SetDsIpDa(V, adMacDaLowBits_f, p_dsipda, ((p_sys_param->param.mac[5]&0x7) | (p_dsnh_info->cloud_sec_en << 3)));
        SetDsIpDa(V, adNextHopSaveEn_f, p_dsipda, 1);

    }
    else if (SYS_USW_GET_DERIVE_MODE == CTC_GLOBAL_MACDA_DERIVE_FROM_NH_ROUTE2 && !p_dsnh_info->cloud_sec_en)
    {
        SetDsIpDa(V, adMacDaLowBits_f, p_dsipda, (p_sys_param->param.mac[5]&0xf));
        SetDsIpDa(V, adNextHopSaveEn_f, p_dsipda, 1);
    }
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_db_init(uint8 lchip)
{
    uint32 entry_num = 0;
    uint32 ad_table_size = 0;
    ctc_spool_t spool;

    SYS_IPUC_INIT_CHECK;

    p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_4]   = ctc_hash_create(SYS_USW_IPUC_HASH_NUM/CTC_HASH_4K_BLOCK_SIZE,
                                CTC_HASH_4K_BLOCK_SIZE,
                                (hash_key_fn)_sys_usw_ipv4_hash_make,
                                (hash_cmp_fn)_sys_usw_ipv4_hash_cmp);

    p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_6]   = ctc_hash_create(SYS_USW_IPUC_HASH_NUM/CTC_HASH_4K_BLOCK_SIZE,
                                CTC_HASH_4K_BLOCK_SIZE,
                                (hash_key_fn)_sys_usw_ipv6_hash_make,
                                (hash_cmp_fn)_sys_usw_ipv6_hash_cmp);

    /* init ad spool */
    if(DRV_FROM_TMM(lchip))
    {
        CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsIp_t, &ad_table_size));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsIpDa_t, &ad_table_size));
    }
    ad_table_size = (ad_table_size + SYS_IPUC_AD_SPOOL_BLOCK_SIZE - 1) /
        SYS_IPUC_AD_SPOOL_BLOCK_SIZE * SYS_IPUC_AD_SPOOL_BLOCK_SIZE;

    sal_memset(&spool, 0, sizeof(ctc_spool_t));
    spool.lchip = lchip;
    spool.block_num = ad_table_size / SYS_IPUC_AD_SPOOL_BLOCK_SIZE;
    spool.block_size = SYS_IPUC_AD_SPOOL_BLOCK_SIZE;
    spool.max_count = ad_table_size;
    spool.user_data_size = CTC_OFFSET_OF(sys_ipuc_ad_spool_t, calc_data_len);
    spool.param_offset = CTC_OFFSET_OF(sys_ipuc_ad_spool_t, param);
    spool.spool_key = (hash_key_fn)_sys_usw_ipuc_ad_profile_make;
    spool.spool_cmp = (hash_cmp_fn)_sys_usw_ipuc_ad_profile_cmp;
    spool.spool_alloc = (spool_alloc_fn)_sys_usw_ipuc_ad_profile_build_index;
    spool.spool_free = (spool_free_fn)_sys_usw_ipuc_ad_profile_free_index;
    p_usw_ipuc_master[lchip]->ad_spool = ctc_spool_create(&spool);
    if (!p_usw_ipuc_master[lchip]->ad_spool)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        return CTC_E_NO_MEMORY;
    }
    if (DRV_FROM_TMM(lchip))
    {
        sys_usw_ftm_query_table_entry_num(lchip, DsNeoLpmIpv4Bit32Snake1_t, &entry_num);
        entry_num = entry_num * 6;
    }
    else
    {
        sys_usw_ftm_query_table_entry_num(lchip, DsLpmLookupKey_t, &entry_num);
    }
    MCHIP_CAP(SYS_CAP_SPEC_LPM_ROUTE_ENTRY_NUM) = entry_num;

    SYS_CB_REGISTER(lchip, SYS_CB_LDP_UPDATE_L3, sys_usw_ipuc_update_ldp_dsip);
    SYS_CB_REGISTER(lchip, SYS_CB_NHID_UPDATE_L3, sys_usw_ipuc_update_dsip_by_nhid);
    if(DRV_FROM_TMM(lchip) || DRV_IS_TSINGMA(lchip))
    {
        uint32 hash_size = MCHIP_CAP(SYS_CAP_NH_MAX_LOGIC_DEST_PORT)/SYS_HASH_SIZE_COMPRESS_RATE_4;
        p_usw_ipuc_master[lchip]->ldp_hash = ctc_hash_create((hash_size + CTC_HASH_1K_BLOCK_SIZE)/CTC_HASH_1K_BLOCK_SIZE, CTC_HASH_1K_BLOCK_SIZE,
                                                        (hash_key_fn)sys_usw_ldp_hash_make,
                                                        (hash_cmp_fn)sys_usw_ldp_hash_cmp);
        if (!p_usw_ipuc_master[lchip]->ldp_hash)
        {
            return CTC_E_NO_MEMORY;
        }

        p_usw_ipuc_master[lchip]->ad_hash = ctc_hash_create(ad_table_size / SYS_IPUC_AD_SPOOL_BLOCK_SIZE, SYS_IPUC_AD_SPOOL_BLOCK_SIZE,
                                                        (hash_key_fn)_sys_usw_ad_hash_make,
                                                        (hash_cmp_fn)_sys_usw_ad_hash_cmp);
        if (!p_usw_ipuc_master[lchip]->ad_hash)
        {
            return CTC_E_NO_MEMORY;
        }
    }
    if(DRV_FROM_TMM(lchip))
    {
        p_usw_ipuc_master[lchip]->nhid_hash = ctc_hash_create((SYS_USW_IPUC_NHID_HASH_SIZE + CTC_HASH_1K_BLOCK_SIZE-1)/CTC_HASH_1K_BLOCK_SIZE, CTC_HASH_1K_BLOCK_SIZE,
                                                        (hash_key_fn)sys_usw_ldp_hash_make,
                                                        (hash_cmp_fn)sys_usw_ldp_hash_cmp);
        if (!p_usw_ipuc_master[lchip]->nhid_hash)
        {
            return CTC_E_NO_MEMORY;
        }
    }
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_db_deinit(uint8 lchip)
{
    LCHIP_CHECK(lchip);
    if(NULL == p_usw_ipuc_master[lchip])
    {
        return CTC_E_NONE;
    }

    ctc_spool_free(p_usw_ipuc_master[lchip]->ad_spool);
    if(!CTC_WB_RT_EN(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO))
    {
        ctc_hash_traverse(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_4], (hash_traversal_fn)sys_usw_ipuc_hash_free_node_data, &lchip);
        ctc_hash_traverse(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_6], (hash_traversal_fn)sys_usw_ipuc_hash_free_node_data, &lchip);
    }
    ctc_hash_free(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_4]);
    ctc_hash_free(p_usw_ipuc_master[lchip]->fib_hash[CTC_IP_VER_6]);
    if(p_usw_ipuc_master[lchip]->ldp_hash)
    {
        ctc_hash_free2(p_usw_ipuc_master[lchip]->ldp_hash, (hash_traversal_fn)sys_usw_free_ldp_node, NULL);
    }
    if(p_usw_ipuc_master[lchip]->nhid_hash)
    {
        ctc_hash_free2(p_usw_ipuc_master[lchip]->nhid_hash, (hash_traversal_fn)sys_usw_free_ldp_node, NULL);
    }
    if(p_usw_ipuc_master[lchip]->ad_hash)
    {
        ctc_hash_free2(p_usw_ipuc_master[lchip]->ad_hash, (hash_traversal_fn)sys_usw_free_ldp_node, NULL);
    }
    return CTC_E_NONE;
}

int32
sys_usw_get_tbl_id(uint8 lchip, uint8 ip_ver, uint8 is_da, sys_ipuc_tbl_type_t tbl_type, uint32* key_id, uint32* ad_id)
{
    uint32 key_tbl_id = 0;
    uint32 ad_tbl_id = 0;

    switch(tbl_type)
    {
        case SYS_TBL_HASH:
            key_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsFibHost0Ipv4HashKey_t : DsFibHost0Ipv6UcastHashKey_t;
            break;
        case SYS_TBL_HASH_NAPT:
            key_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsFibHost1Ipv4NatDaPortHashKey_t : DsFibHost1Ipv6NatDaPortHashKey_t;
            break;
        case SYS_TBL_ALPM:
            if (DRV_IS_DUET2(lchip))
            {
                key_tbl_id = DsLpmLookupKey_t;
            }
            else
            {
                key_tbl_id = DsNeoLpmIpv4Bit32Snake_t;
            }
            break;
        case SYS_TBL_TCAM:
            if (is_da)
            {
                key_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4HalfKey_t : DsLpmTcamIpv6DoubleKey0_t;
                ad_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4HalfKeyAd_t : DsLpmTcamIpv6DoubleKey0Ad_t;
            }
            else
            {
                key_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4SaHalfKey_t : DsLpmTcamIpv6SaDoubleKey0_t;
                ad_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4SaHalfKeyAd_t : DsLpmTcamIpv6SaDoubleKey0Ad_t;
            }
            break;
        case SYS_TBL_TCAM_PUB:
            if (is_da)
            {
                key_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4DaPubHalfKey_t : DsLpmTcamIpv6DaPubDoubleKey0_t;
                ad_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4DaPubHalfKeyAd_t : DsLpmTcamIpv6DaPubDoubleKey0Ad_t;
            }
            else
            {
                key_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4SaPubHalfKey_t : DsLpmTcamIpv6SaPubDoubleKey0_t;
                ad_tbl_id = (ip_ver == CTC_IP_VER_4) ? DsLpmTcamIpv4SaPubHalfKeyAd_t : DsLpmTcamIpv6SaPubDoubleKey0Ad_t;
            }
            break;
        case SYS_TBL_TCAM_SHORT:
            if (is_da)
            {
                key_tbl_id = DsLpmTcamIpv6SingleKey_t;
                ad_tbl_id = DsLpmTcamIpv6SingleKeyAd_t;
            }
            else
            {
                key_tbl_id = DsLpmTcamIpv6SaSingleKey_t;
                ad_tbl_id = DsLpmTcamIpv6SaSingleKeyAd_t;
            }
            break;
        case SYS_TBL_TCAM_PUB_SHORT:
            if (is_da)
            {
                key_tbl_id = DsLpmTcamIpv6DaPubSingleKey_t;
                ad_tbl_id = DsLpmTcamIpv6DaPubSingleKeyAd_t;
            }
            else
            {
                key_tbl_id = DsLpmTcamIpv6SaPubSingleKey_t;
                ad_tbl_id = DsLpmTcamIpv6SaPubSingleKeyAd_t;
            }
            break;
        default:
            key_tbl_id = 0;
            ad_tbl_id = 0;
            break;
    }

    if (key_id)
    {
        *key_id = key_tbl_id;
    }

    if (ad_id)
    {
        *ad_id = ad_tbl_id;
    }

    return CTC_E_NONE;
}

void
sys_usw_ipuc_update_route_stats(uint8 lchip, uint8 ip_ver, sys_ipuc_route_stats_t type, uint8 opt)
{
    if(0 == opt)
    {
        p_usw_ipuc_master[lchip]->route_stats[ip_ver][type]++;
    }
    else
    {
        p_usw_ipuc_master[lchip]->route_stats[ip_ver][type]--;
    }
    return;
}

int32
sys_usw_ipuc_hash_free_node_data(void* node_data, void* user_data)
{
#ifdef CTC_WB_RT_SYNC
    uint8 lchip = *(uint8*)user_data;
#endif

    SYS_WB_FREE(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO,node_data);
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_add_default_entry(uint8 lchip, uint8 ip_ver, uint32 nh_id)
{
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    SYS_IPUC_INIT_CHECK;
    CTC_IP_VER_CHECK(ip_ver);
    SYS_IP_CHECK_VERSION_ENABLE(ip_ver);
    if(lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        return CTC_E_NONE;
    }
    SYS_IPUC_LOCK;
    if(p_usw_ipuc_master[lchip]->default_route_mode)
    {
        SYS_IPUC_UNLOCK;
        return CTC_E_NOT_SUPPORT;
    }
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_MASTER, 1);
    CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_add_default_entry(lchip, ip_ver, 0, nh_id, 0));

    p_usw_ipuc_master[lchip]->default_nhid[ip_ver] = nh_id;

    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_get(uint8 lchip, ctc_ipuc_param_t* p_ctc_param_info)
{
    int32 ret = CTC_E_NONE;
    sys_ipuc_param_t sys_param = {0};
    ipv6_addr_t ipv6;
    DsIpDa_m dsipda;

    SYS_IPUC_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_ctc_param_info);
    sal_memset(&ipv6, 0, sizeof(ipv6_addr_t));
    if (p_ctc_param_info->ip_ver == CTC_IP_VER_6)
    {
        sal_memcpy(&ipv6, &p_ctc_param_info->ip.ipv6, sizeof(ipv6_addr_t));
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, p_ctc_param_info));
    SYS_IP_FUNC_DBG_DUMP(p_ctc_param_info);

    /* para check */
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, p_ctc_param_info, 0, NULL));
    sys_param.param = *p_ctc_param_info;

    SYS_IPUC_LOCK;
    CTC_ERROR_RETURN(_sys_usw_ipuc_db_lookup(lchip, &sys_param));
    if (NULL == sys_param.info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Entry not exist \n");
        ret = CTC_E_NOT_EXIST;
        goto error0;
    }

    sal_memset(p_ctc_param_info->rpf_port, 0, sizeof(uint32) * SYS_RPF_CHK_MODE_IFID);
    if (CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_RPF_CHECK))
    {
        if (sys_param.info->rpf_mode == SYS_RPF_CHK_MODE_IFID)
        {
            p_ctc_param_info->rpf_port_num = 1;
            p_ctc_param_info->rpf_port[0] = sys_param.info->rpf_id;
        }
        else
        {
            uint8 loop = 0;
            uint8 valid = 0;
            uint32 cmd = 0;
            DsRpf_m ds_rpf;

            cmd = DRV_IOR(DsRpf_t, DRV_ENTRY_FLAG);
            CTC_ERROR_GOTO(DRV_IOCTL(lchip, sys_param.info->rpf_id, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &ds_rpf), ret, error0);

            for (loop = 0; loop < SYS_USW_MAX_RPF_IF_NUM; loop++)
            {
                valid = GetDsRpf(V, array_0_rpfIfIdValid_f+loop, &ds_rpf);
                if (0 == valid)
                {
                    break;
                }

                p_ctc_param_info->rpf_port[loop] = GetDsRpf(V, array_0_rpfIfId_f+loop, &ds_rpf);
                p_ctc_param_info->rpf_port_num++;
            }
        }
    }

    if (p_ctc_param_info->ip_ver == CTC_IP_VER_6)
    {
        sal_memcpy(&p_ctc_param_info->ip.ipv6, &ipv6, sizeof(ipv6_addr_t));
    }
    _sys_usw_ipuc_read_ipda( lchip, sys_param.info->ad_index, &dsipda);
    if (CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_ASSIGN_PORT))
    {
       uint32 dest_map = GetDsIpDa(V, destMap_f, &dsipda);
       uint8  gchip = SYS_DECODE_DESTMAP_GCHIP(dest_map);
       uint16  lport = SYS_DECODE_DESTMAP_LPORT(dest_map);
       p_ctc_param_info->gport =  SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip,lport);
    }
    if (CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_STATS_EN))
    {
        uint32 stats_ptr =  0;
        uint16 value;
        if (DRV_FROM_TMM(lchip))
        {
            stats_ptr =  GetDsIpDa(V, statsPtr_f, &dsipda);
        }
        else
        {
            value = GetDsIpDa(V, tunnelGreOption_f, &dsipda);
            stats_ptr = value;
            value = GetDsIpDa(V, tunnelPacketType_f, &dsipda);
            stats_ptr  = stats_ptr | (value <<3);
            value = GetDsIpDa(V, tunnelPayloadOffset_f, &dsipda);
            stats_ptr  = stats_ptr | (value <<6);
            value = GetDsIpDa(V, payloadOffsetType_f, &dsipda);
            stats_ptr  = stats_ptr | (value <<10);
            value  = GetDsIpDa(V, payloadSelect_f, &dsipda);
            stats_ptr  = stats_ptr | (value <<11);
            value =   GetDsIpDa(V, statsPtrHighBits_f, &dsipda);
            stats_ptr  = stats_ptr | (value <<13);
        }
        sys_usw_flow_stats_lookup_statsid(lchip, CTC_STATS_STATSID_TYPE_IP, stats_ptr, &p_ctc_param_info->stats_id, CTC_INGRESS);

    }

    if (DRV_FROM_TMM(lchip))
    {
       if (GetDsIpDa(V, u3Type_f, &dsipda) == 1)
       {
          p_ctc_param_info->cid  = GetDsIpDa(V, u3_g2_categoryId_f, &dsipda);
       }
    }
    else
    {
       if (GetDsIpDa(V, categoryIdValid_f, &dsipda) == 1)
       {
          p_ctc_param_info->cid  = GetDsIpDa(V, categoryId_f, &dsipda);
       }
    }

    p_ctc_param_info->nh_id = sys_param.info->nh_id;
    p_ctc_param_info->l4_dst_port = CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_NAPT) ? sys_param.info->l4_dst_port:0;
    p_ctc_param_info->route_data = GetDsIpDa(V, exceptionSubIndex_f, &dsipda) >> 2;

    p_ctc_param_info->route_flag = 0;
    SYS_IPUC_SYS2CTC_FLAG_CONVERT(p_ctc_param_info->route_flag, sys_param.info->route_flag);

    if(p_ctc_param_info->xdata && CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_XDATA))
    {
        sys_ipuc_xdata_info_t xdata_info;
        sal_memset(&xdata_info, 0, sizeof(xdata_info));

        GetDsIpDa(A, xAdData_f, &dsipda, xdata_info.ds_value);
        p_ctc_param_info->xdata->type = CTC_XDATA_PROF_TYPE_DSIPDA;  /*Only support IPDA xdata*/
        p_ctc_param_info->xdata->prof_id = 0;
        CTC_ERROR_GOTO(_sys_usw_ipuc_get_xdata_withcheck(lchip, p_ctc_param_info->xdata, &xdata_info, &dsipda, 0), ret, error0);
    }
    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;

error0:
    if (p_ctc_param_info->ip_ver == CTC_IP_VER_6)
    {
        sal_memcpy(&p_ctc_param_info->ip.ipv6, &ipv6, sizeof(ipv6_addr_t));
    }
    SYS_IPUC_UNLOCK;
    return ret;
}

int32
sys_usw_ipuc_update_ipda(uint8 lchip, void* data, void* change_nh_param)
{
    sys_ipuc_param_t sys_param = {0};
    sys_ipuc_info_t* p_ipuc_info = (sys_ipuc_info_t*)data;
    sys_nh_info_dsnh_t* p_dsnh_info = change_nh_param;
    sys_nh_info_dsnh_t  dsnh_info = {0};
    DsIpDa_m   dsipda;
    DsIpDa_m   old_dsipda;
    int32 ret = CTC_E_NONE;
    uint32 cmdr  = 0;
    uint32 cmdw  = 0;
    uint32 fwd_offset = 0;
    uint32 old_ad_idx = 0;
    uint8 use_dsfwd = 0;
    uint8 ip_ver = 0;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_IPUC_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_dsnh_info);
    /*do lock when update nexthop, p_dsnh_info is not NULL, otherwise don't lock when bind nexthop*/

    /* ipuc master no need lock */
    if(lchip != (p_usw_ipuc_master[lchip]->master_lchip + p_usw_ipuc_master[lchip]->slave_lchip_cnt - 1))
    {
        return CTC_E_NONE;
    }
    lchip = p_usw_ipuc_master[lchip]->master_lchip;     /* ad spool use master_lchip dsipda to calculate */

    if (p_dsnh_info->need_lock)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "Add Lock\n");
        SYS_IPUC_LOCK;
    }
    ip_ver = (p_dsnh_info->chk_data & 0x80000000)?CTC_IP_VER_6:CTC_IP_VER_4;
    p_dsnh_info->chk_data = p_dsnh_info->chk_data & 0x7fffffff;
    p_ipuc_info = ctc_hash_lookup3(p_usw_ipuc_master[lchip]->fib_hash[ip_ver], &p_dsnh_info->chk_data, p_ipuc_info, &old_ad_idx);
    if (!p_ipuc_info || p_ipuc_info->nh_id != p_dsnh_info->nhid)
    {
        ret = CTC_E_NONE;
        goto out;
    }

    old_ad_idx = p_ipuc_info->ad_index;

    sal_memset(&sys_param, 0, sizeof(sys_param));
    _sys_usw_ipuc_info_to_param(lchip, &sys_param.param, p_ipuc_info);
    sys_param.info = p_ipuc_info;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    sal_memset(&dsipda, 0, sizeof(DsIpDa_m));

    cmdr = DRV_IOR(DsIpDa_t, DRV_ENTRY_FLAG);
    cmdw = DRV_IOW(DsIpDa_t, DRV_ENTRY_FLAG);
    DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmdr, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);

    sal_memcpy(&old_dsipda, &dsipda, sizeof(DsIpDa_m));

    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO, 1);

    use_dsfwd = (p_dsnh_info->merge_dsfwd == 2);
    for(loop_lchip = 0; !use_dsfwd && (loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt); loop_lchip++)
    {
        ret = sys_usw_nh_get_nhinfo(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_ipuc_info->nh_id, &dsnh_info, 0);
        if(ret)/* cant't get nh info in one chip,update route to drop for all chip */
        {
            CTC_ERROR_GOTO(sys_usw_nh_get_nhinfo(lchip + (loop_lchip * SYS_PP_NUM(lchip)), SYS_NH_RESOLVED_NHID_FOR_DROP, &dsnh_info, 0), ret, out);
            p_ipuc_info->nh_id = SYS_NH_RESOLVED_NHID_FOR_DROP;
        }
        if(dsnh_info.dsfwd_valid)
        {
            use_dsfwd = 1;
            break;
        }
    }

    if (use_dsfwd)
    {
        /*update ad from merge dsfwd to using dsfwd*/

        /*1. get dsfwd*/
        CTC_ERROR_GOTO(sys_usw_nh_get_dsfwd_offset(lchip, p_ipuc_info->nh_id, &fwd_offset, 0, CTC_FEATURE_IPUC), ret, out);

        /*2. update ad*/
        if(DRV_IS_TSINGMA(lchip)|| DRV_IS_DUET2(lchip))
        {
            SetDsIpDa(V, nextHopPtrValid_f, &dsipda, 0);
            SetDsIpDa(V, adDestMap_f, &dsipda, 0);
            SetDsIpDa(V, adNextHopPtr_f, &dsipda, 0);
            SetDsIpDa(V, adNextHopExt_f, &dsipda, 0);
            SetDsIpDa(V, adLengthAdjustType_f, &dsipda, 0);
            SetDsIpDa(V, dsFwdPtrOrEcmpGroupId_f, &dsipda, fwd_offset);
        }
        else
        {
            SetDsIpDa(V, u1Type_f, &dsipda, 2);
            SetDsIpDa(V, destMap_f, &dsipda, 0);
            SetDsIpDa(V, nextHopPtr_f, &dsipda, 0);
            SetDsIpDa(V, bypassIngressEdit_f, &dsipda, 0);
            SetDsIpDa(V, nextHopExt_f, &dsipda, 0);
            SetDsIpDa(V, u1_g3_dsFwdPtr_f, &dsipda, fwd_offset);
        }
        CTC_UNSET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_MERGE_KEY);
        CTC_UNSET_FLAG(p_ipuc_info->route_flag, SYS_IPUC_FLAG_IS_BIND_NH);
    }
    else
    {
        sys_nh_info_dsnh_t dsnh_info;
        sal_memset(&dsnh_info, 0, sizeof(sys_nh_info_dsnh_t));
        if(DRV_IS_TSINGMA(lchip)|| DRV_IS_DUET2(lchip))
        {
            if (GetDsIpDa(V, nextHopPtrValid_f, &dsipda) == 0)
            {
                goto out;
            }
        }
        else
        {
            if (GetDsIpDa(V, u1Type_f, &dsipda) == 0)
            {
                goto out;
            }
        }
        CTC_ERROR_DUMP(sys_usw_nh_get_nhinfo(lchip, p_ipuc_info->nh_id, &dsnh_info, 0));
        CTC_ERROR_GOTO(_sys_usw_ipuc_build_ipda_nexthop(lchip, &sys_param, &dsnh_info, &dsipda),ret,error0);
        p_ipuc_info->route_flag &= (p_dsnh_info->drop_pkt == 0xff)?(~SYS_IPUC_FLAG_IS_BIND_NH):0xFFFFFFFF;
    }

    if (!CTC_FLAG_ISSET(p_ipuc_info->route_flag, SYS_IPUC_FLAG_DEFAULT))
    {
        _sys_usw_ipuc_add_ad_profile(lchip, &sys_param, (void*)&dsipda, 1);
    }
    else if(p_usw_ipuc_master[lchip]->default_route_mode)
    {
        p_ipuc_info->ad_index = p_usw_ipuc_master[lchip]->default_base[ip_ver] + p_ipuc_info->vrf_id;
    }

    if(!sys_param.dsipda_built)
    {
        DRV_IOCTL(lchip, p_ipuc_info->ad_index, DRV_CMD_BMP_EN(cmdw, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &dsipda);
        for(loop_lchip = 1; loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt; loop_lchip++)
        {
            CTC_ERROR_GOTO(_sys_usw_ipuc_update_slave_ipda(lchip + (loop_lchip * SYS_PP_NUM(lchip)), p_ipuc_info, &dsipda, use_dsfwd), ret, error1);
        }
    }

    if (old_ad_idx != p_ipuc_info->ad_index)
    {
        /*need update hash key*/
        sys_param.old_ad_index = old_ad_idx;
        if (sys_param.info->route_opt == DO_HASH)
        {
            CTC_ERROR_GOTO(_sys_usw_ipuc_process_hash_key(lchip, &sys_param, DO_UPDATE), ret, error1);
        }
        else if (sys_param.info->route_opt == DO_ALPM)
        {
            if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_update)
            {
                CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->nalpm2_update(lchip, &sys_param, p_ipuc_info->ad_index), ret, error1);
            }
            else if (MCHIP_IPUC(lchip)->alpm_update)
            {
                CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->alpm_update(lchip, &sys_param, p_ipuc_info->ad_index), ret, error1);
            }
        }
        else if (sys_param.info->route_opt == DO_TCAM)
        {
            /* write ipuc tcam key entry */
            CTC_ERROR_GOTO(sys_usw_ipuc_update_tcam(lchip, &sys_param), ret, error1);
        }
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "IPUC update_da: p_ipuc_info->ad_index:0x%x \n", p_ipuc_info->ad_index);
out:
    if (p_dsnh_info->need_lock)
    {
        SYS_IPUC_UNLOCK;
    }
    return CTC_E_NONE;

error1:
    _sys_usw_ipuc_add_ad_profile(lchip, &sys_param, (void*)&old_dsipda, 1);
error0:
    if (p_dsnh_info->need_lock)
    {
        SYS_IPUC_UNLOCK;
    }

    return ret;
}

int32
sys_usw_ipuc_traverse(uint8 lchip, uint8 ip_ver, ctc_ipuc_traverse_fn  fn, void* data)
{
    hash_traversal_fn  fun = _sys_usw_ipuc_traverse_pre;
    sys_ipuc_traverse_t trav;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    SYS_IPUC_INIT_CHECK;
    SYS_IP_CHECK_VERSION_ENABLE(ip_ver);

    trav.data = data;
    trav.fn = fn;
    trav.lchip = lchip;
    if (NULL == fn)
    {
        return CTC_E_NONE;
    }

    return _sys_usw_ipuc_db_traverse(lchip, ip_ver, fun, (void*)&trav);
}

int32
sys_usw_ipuc_host_ftm_cb(uint8 lchip, sys_ftm_specs_info_t* specs_info)
{
    LCHIP_CHECK(lchip);
    SYS_IPUC_INIT_CHECK;
    CTC_PTR_VALID_CHECK(specs_info);

    SYS_IPUC_LOCK;
    if(DRV_IS_DUET2(lchip))
    {
        specs_info->used_size = p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HOST] +
                                              p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HOST] * 2;
        SYS_IPUC_UNLOCK;
        return CTC_E_NONE;
    }

    if(specs_info->type == 0)
    {
        specs_info->used_size = p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HOST];
    }
    else
    {
        specs_info->used_size = p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HOST] * 2;
    }

    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_alpm_ftm_cb(uint8 lchip, sys_ftm_specs_info_t* specs_info)
{
    LCHIP_CHECK(lchip);
    SYS_IPUC_INIT_CHECK;
    CTC_PTR_VALID_CHECK(specs_info);

    SYS_IPUC_LOCK;
    if(DRV_IS_DUET2(lchip))
    {
        specs_info->used_size = p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_ALPM] +
                                              p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_ALPM];
        SYS_IPUC_UNLOCK;
        return CTC_E_NONE;
    }

    if(specs_info->type == 0)
    {
        specs_info->used_size = p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_ALPM];
    }
    else
    {
        specs_info->used_size = p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_ALPM];
    }

    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_set_global_property(uint8 lchip, ctc_ipuc_global_property_t* p_global_prop)
{
    int32 ret = CTC_E_NONE;
    uint32 cmdr = 0;
    uint32 cmdwl = 0;
    uint32 cmdwr = 0;
    ds_t ipe_lookup_route_ctl;
    ds_t ipe_route_ctl;
    void* vall = NULL;
    void* valr = NULL;
    uint32 value1 = 0;
    uint32 value2 = 0;

    SYS_IPUC_INIT_CHECK;
    CTC_PTR_VALID_CHECK(p_global_prop);
    if(lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        return CTC_E_NONE;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&ipe_lookup_route_ctl, 0, sizeof(ipe_lookup_route_ctl));
    sal_memset(&ipe_route_ctl, 0, sizeof(ipe_route_ctl));

    SYS_IPUC_LOCK;
    if (CTC_FLAG_ISSET(p_global_prop->valid_flag, CTC_IP_GLB_PROP_RPF_PERMIT_DEFAULT) && p_usw_ipuc_master[lchip]->default_route_mode)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Permit Default config on Interface When default route mode 1\n");
        SYS_IPUC_UNLOCK;
        return CTC_E_NOT_SUPPORT;
    }

    cmdr = DRV_IOR(IpeLookupRouteCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmdr, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &ipe_lookup_route_ctl), ret, End);

    cmdr = DRV_IOR(IpeRouteCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmdr, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &ipe_route_ctl), ret, End);

    if (CTC_FLAG_ISSET(p_global_prop->valid_flag, CTC_IP_GLB_PROP_V4_MARTIAN_CHECK_EN))
    {
        GetIpeLookupRouteCtl(A, martianCheckEn_f, ipe_lookup_route_ctl, &value1);
        value1 &= 0x7FFF0;  /* clear low 4 bit, flex ipv4(bit[4,5]) modified by register api */
        if (p_global_prop->v4_martian_addr_bmp && p_global_prop->v4_martian_check_en)
        {
            value1 |= (p_global_prop->v4_martian_addr_bmp & 0xF);
        }
        else
        {
            value1 |= (p_global_prop->v4_martian_check_en ? 0xF : 0);
        }
        SetIpeLookupRouteCtl(V, martianCheckEn_f, ipe_lookup_route_ctl, value1);
        value2 = value1 ? 0 : 1;
        SetIpeLookupRouteCtl(V, martianAddressCheckDisable_f, ipe_lookup_route_ctl, value2);

        cmdwl = DRV_IOW(IpeLookupRouteCtl_t, DRV_ENTRY_FLAG);
        vall = &ipe_lookup_route_ctl;
    }

    if (CTC_FLAG_ISSET(p_global_prop->valid_flag, CTC_IP_GLB_PROP_V6_MARTIAN_CHECK_EN))
    {
        GetIpeLookupRouteCtl(A, martianCheckEn_f, ipe_lookup_route_ctl, &value1);
        value1 &= 0x4003F;    /* clear high bit, do not clear ipv6 self define martian address */

        if (p_global_prop->v6_martian_addr_bmp && p_global_prop->v6_martian_check_en)
        {
            value1 |= (p_global_prop->v6_martian_addr_bmp & ((DRV_FROM_TMM(lchip) ? 0x3FFC0 : 0x1FFC0)));
        }
        else
        {
            value1 |= (p_global_prop->v6_martian_check_en) ? (DRV_FROM_TMM(lchip) ? 0x3BFC0 : 0x1BFC0) : 0;
        }
        SetIpeLookupRouteCtl(V, martianCheckEn_f, ipe_lookup_route_ctl, value1);
        value2 = value1 ? 0 : 1;
        SetIpeLookupRouteCtl(V, martianAddressCheckDisable_f, ipe_lookup_route_ctl, value2);

        cmdwl = DRV_IOW(IpeLookupRouteCtl_t, DRV_ENTRY_FLAG);
        vall = &ipe_lookup_route_ctl;
    }

    if (CTC_FLAG_ISSET(p_global_prop->valid_flag, CTC_IP_GLB_PROP_MCAST_MACDA_IP_UNMATCH_CHECK))
    {
        value1 = (p_global_prop->mcast_match_check_en) ? 0 : 1;
        SetIpeRouteCtl(V, mcastAddressMatchCheckDisable_f, ipe_route_ctl, value1);

        cmdwr = DRV_IOW(IpeRouteCtl_t, DRV_ENTRY_FLAG);
        valr = &ipe_route_ctl;
    }

    if (CTC_FLAG_ISSET(p_global_prop->valid_flag, CTC_IP_GLB_PROP_TTL_THRESHOLD))
    {
        value1 = p_global_prop->ip_ttl_threshold;
        SetIpeRouteCtl(V, ipTtlLimit_f, ipe_route_ctl, value1);
        cmdwr = DRV_IOW(IpeTunnelDecapCtl_t,IpeTunnelDecapCtl_ipTtlLimit_f);
        CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmdwr, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &value1), ret, End);

        cmdwr = DRV_IOW(IpeRouteCtl_t, DRV_ENTRY_FLAG);
        valr = &ipe_route_ctl;
    }

    if (cmdwl != 0)
    {
        CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmdwl, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), vall), ret, End);
    }

    if (cmdwr != 0)
    {
        CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmdwr, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), valr), ret, End);
    }

    if (CTC_FLAG_ISSET(p_global_prop->valid_flag, CTC_IP_GLB_PROP_RPF_PERMIT_DEFAULT))
    {
        for (value2 = CTC_IP_VER_4; value2 < MAX_CTC_IP_VER; value2++)
        {
            if (!p_usw_ipuc_master[lchip]->version_en[value2])
            {
                continue;
            }
            value1 = p_global_prop->rpf_permit_default_en ? 0 : 1; /* Permit Default Entry RPF ,unset isCtcDefaultRoute*/
            cmdwl = DRV_IOW(DsIpDa_t,DsIpDa_isCtcDefaultRoute_f);
            CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, p_usw_ipuc_master[lchip]->default_base[value2], DRV_CMD_BMP_EN(cmdwl, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &value1), ret, End);
        }
        p_usw_ipuc_master[lchip]->rpf_permit_default_en = p_global_prop->rpf_permit_default_en ? 1 : 0;
    }
End:
    SYS_IPUC_UNLOCK;
    return ret;
}

int32
sys_usw_ipuc_arrange_fragment(uint8 lchip)
{
    sys_ipuc_param_list_t *p_param_list = NULL;
    sys_ipuc_param_list_t *p_param_cur = NULL;
    sys_ipuc_param_list_t *p_cur = NULL;
    sys_ipuc_traverse_t trav_data = {0};
    uint8  ip_ver = 0;
    uint16  vrf = 0;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_INIT_CHECK;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_IPUC_LOCK;

    if(DRV_FROM_TM(lchip)&& MCHIP_IPUC(lchip)->alpm_merge)
    {
        for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
        {
            for (vrf = 0; vrf <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); vrf++)
            {
                ret = MCHIP_IPUC(lchip)->alpm_merge(lchip, vrf, ip_ver);
            }
        }
        SYS_IPUC_UNLOCK;
        return ret;
    }
    else if(DRV_IS_DUET2(lchip))
    {
        p_param_list = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_ipuc_param_list_t), sys_ipuc_param_list_t);
        if (NULL == p_param_list)
        {
            SYS_IPUC_UNLOCK;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_param_list, 0, sizeof(sys_ipuc_param_list_t));

        trav_data.lchip = lchip;
        trav_data.data = (void*)p_param_list;
        trav_data.data1 = (void*)p_param_list;

        for(ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
        {
            /* prepare sort table */
            _sys_usw_ipuc_db_traverse(lchip, ip_ver, _sys_usw_ipuc_db_get_info_cb, &trav_data);
            if ((ip_ver == CTC_IP_VER_6) && (trav_data.data != trav_data.data1))
            {
                p_cur = (sys_ipuc_param_list_t *)trav_data.data;
                mem_free(p_cur->p_next_param);
                p_cur->p_next_param = NULL;
            }
        }

        /* ipuc count must bigger than one */
        if (p_param_list->p_next_param)
        {
            if (MCHIP_IPUC(lchip)->alpm_arrange_fragment)
            {
                CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->alpm_arrange_fragment(lchip, p_param_list));
            }
        }

        while(p_param_list)
        {
            p_param_cur = p_param_list;
            p_param_list = p_param_cur->p_next_param;
            mem_free(p_param_cur->p_ipuc_param);
            mem_free(p_param_cur);
        }
    }
    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_set_entry_hit(uint8 lchip, ctc_ipuc_param_t* p_ipuc_param, uint8 hit)
{
    sys_ipuc_param_t sys_param = {0};
    uint32 ret = CTC_E_NONE;
    uint32 key_index = 0;
    uint8 domain_type = 0;

    SYS_IPUC_INIT_CHECK;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* para check */
    sal_memcpy(&sys_param.param, p_ipuc_param, sizeof(ctc_ipuc_param_t));

    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, &sys_param.param));
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, &sys_param.param, 1, NULL));

    SYS_IP_FUNC_DBG_DUMP(p_ipuc_param);

    SYS_IPUC_LOCK;
    /*check entry exist*/
    CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_db_lookup(lchip, &sys_param));
    if (!sys_param.info)
    {
        CTC_RETURN_IPUC_UNLOCK(CTC_E_NOT_EXIST);
    }
    if(DRV_FROM_TMM(lchip))
    {
        if(sys_param.info->route_opt == DO_ALPM)
        {
            hit = hit ? 1:0;
            #if defined(TSINGMA_MX) || defined(TSINGMA_GX) || defined(ARCTIC)
            if (p_usw_ipuc_master[lchip]->multi_level)
            {
                #if defined(ARCTIC)
                ret = sys_nalpm2_ageing_opt(lchip, &sys_param, IPUC_LPM_AGING_SET, &hit);
                #endif
                SYS_IPUC_UNLOCK;
                return ret;
            }
            else
            {
                ret = sys_tmm_nalpm_ageing_opt(lchip, &sys_param, IPUC_LPM_AGING_SET, &hit);
                SYS_IPUC_UNLOCK;
                return ret;
            }
            #endif
        }
    }
    else
    {
        if(sys_param.info->route_opt != DO_HASH || CTC_FLAG_ISSET(p_ipuc_param->route_flag, CTC_IPUC_FLAG_HOST_USE_LPM))
        {
            CTC_RETURN_IPUC_UNLOCK(CTC_E_NOT_SUPPORT);
        }
     }
    domain_type = (sys_param.info->route_opt == DO_HASH)?\
        (CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_NAPT)?SYS_AGING_DOMAIN_HOST1:SYS_AGING_DOMAIN_IP_HASH):\
        SYS_AGING_DOMAIN_TCAM;
    hit = hit ? 1:0;
    MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;

    if(sys_param.info->route_opt == DO_HASH)
    {
        CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_process_hash_key(lchip, &sys_param, DO_LOOKUP));
    }
    key_index = sys_param.info->key_index;

    if(sys_param.info->route_opt == DO_TCAM &&
       (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP) ||
        CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6], SYS_TCAM_PUB_LOOKUP) ||
        CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6], SYS_TCAM_SHORT_LOOKUP)))
    {
        uint16 tcam_bound = 0;
        tcam_bound = DRV_IS_TSINGMA(lchip) ? 4096 : 8192;
        /*  See drv_ftm ,lpm_tcam_init_bmp
            pub_bound_low = DRV_IS_TSINGMA(lchip) ? 4096 : 8192;
            pri_bound_low = DRV_IS_TSINGMA(lchip) ? 4096 : 8192;
            pub_bound_high = DRV_IS_TSINGMA(lchip) ? 4096 : 8192; */
        if(CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE))
        {
            key_index = key_index >= tcam_bound ? /* pub_bound_low */
                                    (key_index + tcam_bound) /* pri_bound_low */
                                    : key_index;
        }
        else
        {
            if(!DRV_IS_AT(lchip))
            {
                key_index = key_index >= tcam_bound ? /* pri_bound_low */
                        (key_index + tcam_bound) /* pub_bound_high */
                        : key_index;
            }
            key_index += tcam_bound; /* pub_bound_low */
        }
    }

    ret = sys_usw_aging_set_aging_status(lchip, domain_type, key_index, 0, hit);
    SYS_IPUC_UNLOCK;

    return ret;
}

int32
sys_usw_ipuc_get_entry_hit(uint8 lchip, ctc_ipuc_param_t* p_ipuc_param, uint8* hit)
{
    sys_ipuc_param_t sys_param = {0};
    uint32 ret = CTC_E_NONE;
    uint32 key_index = 0;
    uint8 domain_type = 0;

    SYS_IPUC_INIT_CHECK;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* para check */
    sal_memcpy(&sys_param.param, p_ipuc_param, sizeof(ctc_ipuc_param_t));

    CTC_PTR_VALID_CHECK(hit);
    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, &sys_param.param));
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, &sys_param.param, 1, NULL));
    SYS_IP_FUNC_DBG_DUMP(p_ipuc_param);

    SYS_IPUC_LOCK;
    /*check entry exist*/
    CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_db_lookup(lchip, &sys_param));
    if (!sys_param.info)
    {
        CTC_RETURN_IPUC_UNLOCK(CTC_E_NOT_EXIST);
    }

    if(DRV_FROM_TMM(lchip))
    {
        if(sys_param.info->route_opt == DO_ALPM)
        {
            #if defined(TSINGMA_MX) || defined(TSINGMA_GX) || defined(ARCTIC)
            if (p_usw_ipuc_master[lchip]->multi_level)
            {
                #if defined(ARCTIC)
                ret = sys_nalpm2_ageing_opt(lchip, &sys_param, IPUC_LPM_AGING_GET, hit);
                #endif
                SYS_IPUC_UNLOCK;
                return ret;
            }
            else
            {
                ret = sys_tmm_nalpm_ageing_opt(lchip, &sys_param, IPUC_LPM_AGING_GET, hit);
                SYS_IPUC_UNLOCK;
                return ret;
            }
            #endif
        }
        else
        {
            if(sys_param.info->route_opt == DO_HASH)
            {
                domain_type = CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_NAPT)?SYS_AGING_DOMAIN_HOST1:SYS_AGING_DOMAIN_IP_HASH;
            }
            else if(sys_param.info->route_opt == DO_TCAM)
            {
                domain_type = SYS_AGING_DOMAIN_TCAM;
            }
        }
    }
    else
    {
        if(sys_param.info->route_opt != DO_HASH)
        {
            CTC_RETURN_IPUC_UNLOCK(CTC_E_NOT_SUPPORT);
        }
        domain_type = (sys_param.info->route_opt == DO_HASH)?\
            (CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_NAPT)?SYS_AGING_DOMAIN_HOST1:SYS_AGING_DOMAIN_IP_HASH):\
            SYS_AGING_DOMAIN_TCAM;
    }
    MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;

    if(sys_param.info->route_opt == DO_HASH)
    {
        CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_process_hash_key(lchip, &sys_param, DO_LOOKUP));
    }
    key_index = sys_param.info->key_index;

    if(sys_param.info->route_opt == DO_TCAM &&
       (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP) ||
        CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6], SYS_TCAM_PUB_LOOKUP) ||
        CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6], SYS_TCAM_SHORT_LOOKUP)))
    {
        uint16 tcam_bound = 0;
        tcam_bound = DRV_IS_TSINGMA(lchip) ? 4096 : 8192;
        /*  See drv_ftm ,lpm_tcam_init_bmp
            pub_bound_low = DRV_IS_TSINGMA(lchip) ? 4096 : 8192;
            pri_bound_low = DRV_IS_TSINGMA(lchip) ? 4096 : 8192;
            pub_bound_high = DRV_IS_TSINGMA(lchip) ? 4096 : 8192; */
        if(CTC_FLAG_ISSET(sys_param.info->route_flag, SYS_IPUC_FLAG_PUBLIC_ROUTE))
        {
            key_index = key_index >= tcam_bound ? /* pub_bound_low */
                                    (key_index + tcam_bound) /* pri_bound_low */
                                    : key_index;
        }
        else
        {
            if(!DRV_IS_AT(lchip))
            {
                key_index = key_index >= tcam_bound ? /* pri_bound_low */
                        (key_index + tcam_bound) /* pub_bound_high */
                        : key_index;
            }
            key_index += tcam_bound; /* pub_bound_low */
        }
    }

    ret = sys_usw_aging_get_aging_status(lchip, domain_type, key_index, hit);
    SYS_IPUC_UNLOCK;

    return ret;
}

#define __1_SHOW__
int32
sys_usw_ipuc_get_tcam_memusage(uint8 lchip, uint8 sub_type, uint32* total_size, uint32* used_size)
{
    SYS_IPUC_INIT_CHECK;
    *total_size = (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM]+p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT]+
                       p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM]) + p_usw_ip_tunnel_master[lchip]->max_snat_tcam_num*4;
    if(sub_type == 0)
    {
        *used_size = (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM] +(p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM_SHORT] * 2 +
                                    p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM] * 4));
        *used_size += p_usw_ip_tunnel_master[lchip]->snat_tcam_count*4;
    }
    else if (sub_type == 1)
    {
        *used_size = p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM] + p_usw_ip_tunnel_master[lchip]->snat_tcam_count*4;
    }
    else
    {
        *used_size = (p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM_SHORT] * 2 +
                                    p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM] * 4);
    }

    return CTC_E_NONE;
}



int32
sys_usw_ipuc_db_show(uint8 lchip,
                ctc_ip_ver_t            ip_ver,
                sys_ipuc_info_t         *p_ipuc_data,
                uint32                  detail)
{
    SYS_IPUC_INIT_CHECK;
    SYS_IPUC_LOCK;
    _sys_usw_ipuc_db_show(lchip, ip_ver, p_ipuc_data, detail);
    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

#if (SDK_WORK_PLATFORM == 1)
extern int32
drv_model_ipuc_lookup(uint8 lchip, uint8 ip_ver, uint32* ip, uint32 vrf_id, uint32 *nexthop);
#endif


int32
sys_usw_ipuc_hw_check(uint8 lchip, trie_chk_info_t *info, uint32* ip_key)
{
    uint32 nexthop[8] = {0};
    uint32 ad_index = info->ad_idx;


#if (SDK_WORK_PLATFORM == 1)
    drv_model_ipuc_lookup(lchip, info->ip_ver, ip_key, info->vrf_id, nexthop);
#endif
    if(DRV_FROM_AT(lchip))
    {
        ad_index = ((ad_index & 0x3ffff) == 0x3fffe) ? 0x3ffff : ad_index;
    }
    if(info->detail || (nexthop[0] != (ad_index & 0x3ffff)))
    {
        char buf[CTC_IPV6_ADDR_STR_LEN];
        char buf_match[CTC_IPV6_ADDR_STR_LEN];
        char buf2[SYS_IPUC_MASK_LEN] = {0};

        sal_sprintf(buf2, "/%d", info->mask_len);

        if (info->ip_ver == CTC_IP_VER_4)
        {
            uint32 tempip = sal_ntohl(*info->ip);
            sal_inet_ntop(AF_INET, &tempip, buf, CTC_IPV6_ADDR_STR_LEN);
            sal_strncat(buf, buf2, SYS_IPUC_MASK_LEN);

            tempip = sal_ntohl(ip_key[0]);
            sal_inet_ntop(AF_INET, &tempip, buf_match, CTC_IPV6_ADDR_STR_LEN);
            sal_strncat(buf_match, buf2, SYS_IPUC_MASK_LEN);

        }
        else
        {
            uint32 ipv6_address[4] = {0, 0, 0, 0};

            ipv6_address[0] = sal_ntohl(info->ip[0]);
            ipv6_address[1] = sal_ntohl(info->ip[1]);
            ipv6_address[2] = sal_ntohl(info->ip[2]);
            ipv6_address[3] = sal_ntohl(info->ip[3]);

            sal_inet_ntop(AF_INET6, ipv6_address, buf, CTC_IPV6_ADDR_STR_LEN);
            sal_strncat(buf, buf2, SYS_IPUC_MASK_LEN);

            ipv6_address[0] = sal_ntohl(ip_key[0]);
            ipv6_address[1] = sal_ntohl(ip_key[1]);
            ipv6_address[2] = sal_ntohl(ip_key[2]);
            ipv6_address[3] = sal_ntohl(ip_key[3]);

            sal_inet_ntop(AF_INET6, ipv6_address, buf_match, CTC_IPV6_ADDR_STR_LEN);
            sal_strncat(buf_match, buf2, SYS_IPUC_MASK_LEN);

        }

        if (info->detail  || (nexthop[0] != ad_index))
        {

            if (nexthop[0] != ad_index)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "FAIL!!! ");
            }


            if (DRV_IS_TSINGMA(lchip))
            {    /*(snakeLookupResult(1,0),snakeHitNumber(3,0))*/
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-5d %-44s:%-44s, AD E:%d, R:%d, TcamHit:%d SramIdx:%d, g:%d, i:%d, j:%d\n",
                    info->vrf_id, buf, buf_match, info->ad_idx, nexthop[0], nexthop[1], nexthop[2], nexthop[3] >> 6, (((nexthop[3] >> 4)&0x3) == 1)?0:1, (nexthop[3])&0xF);
            }
            else
            {    /*(lpmHitGroupId,lpmHitMemoryId(2,0),lpmHitNumber(2,0))*/
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-5d %-44s:%-44s, AD E:%d, R:%d, TcamHit:%d SramIdx:%d, g:%d, i:%d, j:%d\n",
                    info->vrf_id, buf, buf_match, info->ad_idx, nexthop[0], nexthop[1], nexthop[2], nexthop[3] >> 6, (nexthop[3] >> 3)&0x7, (nexthop[3])&0x7);
            }
        }
    }

    return 0;
}


int32
sys_usw_ipuc_check_cb(sys_ipuc_info_t* p_ipuc_data, void* data)
{
    uint8 lchip = 0;
    uint8 detail = 0;
    uint8 ip_ver = 0;
    uint32 ip[4] = {0};
    trie_chk_info_t info;

    sal_memset(&info, 0, sizeof(trie_chk_info_t));
    detail = *((uint8*)(((sys_ipuc_traverse_t*)data)->data));
    lchip  = ((sys_ipuc_traverse_t*)data)->lchip;

    if (SYS_IPUC_VER(p_ipuc_data) == CTC_IP_VER_4)
    {
        ip[0] = p_ipuc_data->ip.ipv4;
        ip_ver = 0;
    }
    else
    {
        ip[0] = p_ipuc_data->ip.ipv6[3];
        ip[1] = p_ipuc_data->ip.ipv6[2];
        ip[2] = p_ipuc_data->ip.ipv6[1];
        ip[3] = p_ipuc_data->ip.ipv6[0];
        ip_ver = 1;
    }

    info.ip_ver = ip_ver;
    info.vrf_id = p_ipuc_data->vrf_id;
    info.ip = ip;
    info.mask_len = p_ipuc_data->masklen;
    info.ad_idx = p_ipuc_data->ad_index;
    info.detail = detail;

    if (p_usw_ipuc_master[lchip]->multi_level)
    {
        if (p_ipuc_data->route_opt == DO_ALPM && MCHIP_IPUC(lchip)->nalpm2_check_route)
        {
            MCHIP_IPUC(lchip)->nalpm2_check_route(lchip, &info, sys_usw_ipuc_hw_check);
        }
    }
    else
    {
        if (p_ipuc_data->route_opt == DO_ALPM && MCHIP_IPUC(lchip)->alpm_check_route_info)
        {
            MCHIP_IPUC(lchip)->alpm_check_route_info(lchip, &info, sys_usw_ipuc_hw_check);
        }
    }

    return CTC_E_NONE;
}

int32
sys_usw_ipuc_db_check(uint8 lchip,  uint8 ip_ver, uint8 detail)
{
#if (SDK_WORK_PLATFORM == 1)
    sys_ipuc_traverse_t travs;

    SYS_IPUC_INIT_CHECK;

    travs.data = &detail;
    travs.lchip = lchip;

    _sys_usw_ipuc_db_traverse(lchip, ip_ver, (hash_traversal_fn)sys_usw_ipuc_check_cb, (void*)&travs);
#endif

    return CTC_E_NONE;
}

int32
sys_usw_ipuc_check_route(uint8 lchip,  ctc_ipuc_param_t* p_ctc_param_info, uint8 detail)
{
#if (SDK_WORK_PLATFORM == 1)
    sys_ipuc_traverse_t travs;
    sys_ipuc_param_t sys_param = {0};
    sys_nh_info_dsnh_t nhinfo;
    travs.data = &detail;
    travs.lchip = lchip;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_IPUC_INIT_CHECK;

    sal_memset(&nhinfo, 0, sizeof(sys_nh_info_dsnh_t));

    SYS_IPUC_INIT_CHECK;
    sal_memcpy(&sys_param.param, p_ctc_param_info, sizeof(ctc_ipuc_param_t));

    /* 1. param check and debug out */
    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, &sys_param.param));
    SYS_IP_FUNC_DBG_DUMP(p_ctc_param_info);

    /* para check */
    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo(lchip, sys_param.param.nh_id, &nhinfo, 0));
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, &sys_param.param, 1, &nhinfo));

    /* 2. lookup sw node */
    CTC_ERROR_RETURN(_sys_usw_ipuc_db_lookup(lchip, &sys_param));
    if (NULL == sys_param.info)
    {
        return CTC_E_NOT_EXIST;
    }

    sys_usw_ipuc_check_cb(sys_param.info, &travs);


#endif

    return CTC_E_NONE;
}

int32
_sys_usw_ipuc_show_martian_addrs(uint8 lchip)
{
    ds_t ipe_lookup_route_ctl = {0};
    ds_t ipe_route_martian_addr = {0};
    char buf[CTC_IPV6_ADDR_STR_LEN] = {0};
    ipv6_addr_t ip_addr = {0};
    ipv6_addr_t ip_addr_mask = {0};
    uint32 en_bitmap = 0;
    uint32 cmd = 0;
    uint8 masklen = 0;
    uint8 num = 0;
    uint8 valid = 0;

    cmd = DRV_IOR(IpeRouteMartianAddr_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_route_martian_addr));
    cmd = DRV_IOR(IpeLookupRouteCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, cmd, &ipe_lookup_route_ctl));

    GetIpeLookupRouteCtl(A, martianCheckEn_f, ipe_lookup_route_ctl, &en_bitmap);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------Martian address-------------------------------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "No| Address%37s Valid\n", " ");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------IPv4 Martian address For SA-------------------------------------\n");
    /* Only for SA */
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "224.0.0.0/4", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "240.0.0.0/4", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "127.0.0.0/8", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "0.0.0.0/8", valid);

    GetIpeRouteMartianAddr(A, flex0Value_f, ipe_route_martian_addr, &ip_addr[0]);
    GetIpeRouteMartianAddr(A, flex0Mask_f, ipe_route_martian_addr, &ip_addr_mask[0]);
    IPV4_MASK_TO_LEN(ip_addr_mask[0], masklen);
    IPUC_GEN_IP_STR(buf, CTC_IP_VER_4, ip_addr, masklen);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d  User define\n", num++, buf, valid);

    GetIpeRouteMartianAddr(A, flex1Value_f, ipe_route_martian_addr, &ip_addr[0]);
    GetIpeRouteMartianAddr(A, flex1Mask_f, ipe_route_martian_addr, &ip_addr_mask[0]);
    IPV4_MASK_TO_LEN(ip_addr_mask[0], masklen);
    IPUC_GEN_IP_STR(buf, CTC_IP_VER_4, ip_addr, masklen);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d  User define\n", num++, buf, valid);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------IPv6 Martian address For SA-------------------------------------\n");

    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "2002:{v4 martian addrs}::0/48", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "0::FFFF:{v4 martian addrs}/128", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "0::{v4 martian addrs}/128", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "FF00::0/8", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "0::0001/128", valid);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------IPv6 Martian address For Both DA and SA-------------------------\n");

    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "0064:FF9B::0/96", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "3FFE::0/16", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "5F00::0/8", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "2001:0010::0/28", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "2001:0DB8::0/32", valid);
    valid = CTC_IS_BIT_SET(en_bitmap,num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "FC00::0/7", valid);

    if(DRV_FROM_TMM(lchip))
    {
        valid = CTC_IS_BIT_SET(en_bitmap,num);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d\n", num++, "2001:0020::0/28", valid);

        sal_memset(ip_addr, 0 ,sizeof(ip_addr));
        GetIpeLookupRouteCtl(A, martianAddr_f, ipe_lookup_route_ctl, ip_addr);
        GetIpeLookupRouteCtl(A, martianAddrMask_f, ipe_lookup_route_ctl, ip_addr_mask);
        IPV6_MASK_TO_LEN(ip_addr_mask, masklen);
        IPUC_GEN_IP_STR(buf, CTC_IP_VER_6, ip_addr, masklen);
        valid = CTC_IS_BIT_SET(en_bitmap,num);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%2d: %-44s    %d  User define\n", num++, buf, valid);
    }

    return CTC_E_NONE;
}

int32
sys_usw_ipuc_show_status(uint8 lchip)
{
    uint8 v4_frag_status = 0;
    uint8 v6_frag_status = 0;
    int32 ret = 0;
    SYS_IPUC_INIT_CHECK;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------Default action--------------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s%s\n", "TYPE", " ", "Nexthop", " ", "AD");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");
    for(v4_frag_status = 0;v4_frag_status < MAX_CTC_IP_VER;v4_frag_status++)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-19s%-19d%u", CTC_IP_VER_4 == v4_frag_status?"--IPv4":"--IPv6", p_usw_ipuc_master[lchip]->default_nhid[v4_frag_status], p_usw_ipuc_master[lchip]->default_base[v4_frag_status]);
        if(p_usw_ipuc_master[lchip]->default_route_mode)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-%d",p_usw_ipuc_master[lchip]->default_base[v4_frag_status]+MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));
        }
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------SPEC Resource Usage---------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s%s\n", "TYPE", " ", "SPEC", " ", "COUNT");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15d\n", "HOST Route", " ", SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_HOST)+SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_ND));
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15d%-4s%d\n", "--IPv4", " ", SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_HOST), " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HOST]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15d%-4s%d\n", "--IPv6", " ", SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_ND), " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HOST]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15d\n", "LPM Route", " ", SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_LPM)+SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_LPMv6));
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15d%-4s%d\n", "--IPv4", " ", SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_LPM), " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_LPM]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15d%-4s%d\n", "--IPv6", " ", SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_IPUC_LPMv6), " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_LPM]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------Memory Usage----------------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s%-15s%-4s%-15s\n", "TYPE", " ", "SIZE", " ", "Entries", " ", "Usage");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_HASH_LOOKUP))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%d\n", "Hash", " ", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_HASH] + DRV_CONST(DRV_FIB_HOST0_CAM_NUM));
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s", "--IPv4", " ", "-", " ");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15d%-4s%-15d\n", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HASH], " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HASH]);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s", "--IPv6", " ", "-", " ");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15d%-4s%-15d\n", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HASH], " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HASH] * 2);
    }

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_LOOKUP))
    {
        if (MCHIP_IPUC(lchip)->show_tcam_status)
        {
            MCHIP_IPUC(lchip)->show_tcam_status(lchip, NULL);
        }
    }

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s\n", "ALPM", " ");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s", "--IPv4", " ", "/", " ");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15d%-4s%-15s\n", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_ALPM], " ", "/");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s", "--IPv6", " ", "/", " ");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15d%-4s%-15s\n", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_ALPM], " ", "/");
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");


    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n\n");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------ALPM Status----------------------------------\n");
        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_show_status)
        {
            MCHIP_IPUC(lchip)->nalpm2_show_status(lchip);
        }
        else if (MCHIP_IPUC(lchip)->alpm_show_status)
        {
            MCHIP_IPUC(lchip)->alpm_show_status(lchip);
        }
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------Hash Conflict Status--------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-10s\n", "TYPE", " ", "COUNT");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s\n", "In TCAM");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%d\n", "--IPv4", " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_CONFLICT_TCAM]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%d\n", "--IPv6", " ", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_CONFLICT_TCAM]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------Nat Status------------------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s%-15s%-4s%s\n", "TYPE", " ", "SIZE", " ", "COUNT");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s", "IPV4 SNAT Tcam", " ");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15d%-4s",  p_usw_ip_tunnel_master[lchip]->max_snat_tcam_num, " ");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%d\n", p_usw_ip_tunnel_master[lchip]->snat_tcam_count);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s", "IPV4 SNAT Hash", " ");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15d%-4s",  (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_HASH_NAPT] ?
        SYS_FTM_SPEC(lchip, CTC_FTM_SPEC_NAPT) : 0), " ");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%d\n", p_usw_ip_tunnel_master[lchip]->snat_hash_count);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s", "IPV4 NAPT Hash", " ");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-15s%-4s",  (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_HASH_NAPT] ?
        "-" : "0"), " ");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%d\n", p_usw_ip_tunnel_master[lchip]->napt_hash_count);
    if (DRV_IS_TSINGMA(lchip))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------------------------------------------------------------\n");

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "LPM TCAM usage v4:%u/%u, v6:%u/%u\n",
                         p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[CTC_IP_VER_4],
                         p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_4],
                         p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[CTC_IP_VER_6],
                         p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_6]);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------\n");
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Auto resolve conflict v4:%d, v6:%d\n",
                         p_usw_ipuc_master[lchip]->arc[CTC_IP_VER_4],
                         p_usw_ipuc_master[lchip]->arc[CTC_IP_VER_6]);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------\n");

        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_show_sram_usage)
        {
            ret = MCHIP_IPUC(lchip)->nalpm2_show_sram_usage(lchip);
        }
        else if (MCHIP_IPUC(lchip)->show_sram_usage)
        {
            ret = MCHIP_IPUC(lchip)->show_sram_usage(lchip);
        }

        if(CTC_E_NOT_INIT == ret)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Feature not initialized\n");
        }

        if (MCHIP_IPUC(lchip)->alpm_get_fragment_status)
        {
            ret = MCHIP_IPUC(lchip)->alpm_get_fragment_status(lchip, CTC_IP_VER_4, &v4_frag_status);
            ret = MCHIP_IPUC(lchip)->alpm_get_fragment_status(lchip, CTC_IP_VER_6, &v6_frag_status);
            if(CTC_E_NOT_INIT == ret)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------\n");
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Feature not initialized\n");
            }
            else
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------\n");
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "IPv4 Merge status: %u\n", v4_frag_status);
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "IPv6 Merge status: %u\n", v6_frag_status);
            }
        }
    }

    CTC_ERROR_RETURN(_sys_usw_ipuc_show_martian_addrs(lchip));

    return CTC_E_NONE;
}

int32
sys_usw_ipuc_show_debug_info(uint8 lchip, ctc_ipuc_param_t* p_ctc_param_info)
{
    sys_ipuc_param_t sys_param = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_IPUC_INIT_CHECK;

    sal_memcpy(&sys_param.param, p_ctc_param_info, sizeof(ctc_ipuc_param_t));
    /* 1. param check and debug out */
    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, &sys_param.param));
    SYS_IP_FUNC_DBG_DUMP((&sys_param.param));

    /* para check */
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, &sys_param.param, 0, NULL));

    SYS_IPUC_LOCK;
    /* lookup for ipuc entrise */
    CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_db_lookup(lchip, &sys_param));
    if (!sys_param.info)
    {
        CTC_RETURN_IPUC_UNLOCK(CTC_E_NOT_EXIST);
    }

    CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_db_show(lchip, sys_param.param.ip_ver, sys_param.info, 1));

    SYS_IPUC_UNLOCK;

    return CTC_E_NONE;
}

extern int32
sys_usw_ipuc_dump_ipuc_info(uint8 lchip, ctc_ipuc_param_t* p_ctc_param_info)
{
    sys_ipuc_param_t sys_param = {0};
    uint32 detail = 0;
    sys_ipuc_traverse_t travs;


    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_IPUC_INIT_CHECK;
    sal_memset(&travs, 0, sizeof(sys_ipuc_traverse_t));

    sal_memcpy(&sys_param.param, p_ctc_param_info, sizeof(ctc_ipuc_param_t));
    /* 1. param check and debug out */
    CTC_ERROR_RETURN(_sys_usw_ipuc_check(lchip, &sys_param.param));
    SYS_IP_FUNC_DBG_DUMP((&sys_param.param));

    /* para check */
    CTC_ERROR_RETURN(_sys_usw_ipuc_flag_check(lchip, &sys_param.param, 0, NULL));

    SYS_IPUC_LOCK;
    /* lookup for ipuc entrise */
    CTC_ERROR_RETURN_IPUC_UNLOCK(_sys_usw_ipuc_db_lookup(lchip, &sys_param));
    if (!sys_param.info)
    {
        CTC_RETURN_IPUC_UNLOCK(CTC_E_NOT_EXIST);
    }

    travs.data = &detail;
    travs.lchip = lchip;

    if(sys_param.info)
    {
        _sys_usw_show_ipuc_info(sys_param.info, (void*)&travs);
    }

    SYS_IPUC_UNLOCK;

    return CTC_E_NONE;
}

int32
sys_usw_ipuc_dump_db(uint8 lchip, sal_file_t p_f, ctc_global_dump_db_t* p_dump_param)
{
    int32 ret = CTC_E_NONE;
    uint32 cnt = 1;
    uint32 value = 0;
    uint32 cmd = 0;
    uint8 mode = 1;
    sys_dump_db_traverse_param_t    cb_data;
    sal_memset(&cb_data, 0, sizeof(sys_dump_db_traverse_param_t));
    cb_data.value0 = p_f;
    cb_data.value1 = &cnt;
    cb_data.value2 = &mode;
    cb_data.lchip = lchip;

    SYS_IPUC_INIT_CHECK;
    SYS_IPUC_LOCK;
    SYS_DUMP_DB_LOG(p_f, "%s\n", "# IPUC");
    SYS_DUMP_DB_LOG(p_f, "%s\n", "{");
    SYS_DUMP_DB_LOG(p_f, "%s\n", "Master config:");
    SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPUC default route mode",p_usw_ipuc_master[lchip]->default_route_mode);
    SYS_DUMP_DB_LOG(p_f, "%-40s\n", "Default action:");
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv4 default base", p_usw_ipuc_master[lchip]->default_base[CTC_IP_VER_4]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv6 default base", p_usw_ipuc_master[lchip]->default_base[CTC_IP_VER_6]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv4 default nexthop", p_usw_ipuc_master[lchip]->default_nhid[CTC_IP_VER_4]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv6 default nexthop", p_usw_ipuc_master[lchip]->default_nhid[CTC_IP_VER_6]);
    SYS_DUMP_DB_LOG(p_f, "%-40s\n", "Spec:");
    SYS_DUMP_DB_LOG(p_f, "%-40s\n", "--IPv4:");
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Hash", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_HASH]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Hash NAPT:", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_HASH_NAPT]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "ALPM:", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_ALPM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM:", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM PUB", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM_PUB]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM SHORT", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM PUB SHORT", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM_PUB_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "%-40s\n", "--IPv6:");
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Hash", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_HASH]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Hash NAPT", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_HASH_NAPT]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "ALPM", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_ALPM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM PUB", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM SHORT", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "TCAM PUB SHORT", p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "%-40s\n", "Route stats:");
    SYS_DUMP_DB_LOG(p_f, "%-40s\n", "--IPv4:");
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Host", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HOST]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "LPM", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_LPM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "HASH", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_HASH]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "ALPM", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_ALPM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Conflict Tcam", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_CONFLICT_TCAM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam Pub", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM_PUB]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam Short", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam Pub Short", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_4][SYS_IPUC_TCAM_PUB_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "%-40s\n", "--IPv6:");
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Host", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HOST]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "LPM", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_LPM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "HASH", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_HASH]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "ALPM", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_ALPM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Conflict Tcam", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_CONFLICT_TCAM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam Pub", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM_PUB]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam Short", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "  %-38s: %u\n", "Tcam Pub Short", p_usw_ipuc_master[lchip]->route_stats[CTC_IP_VER_6][SYS_IPUC_TCAM_PUB_SHORT]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Short key boundary(Private mode)", p_usw_ipuc_master[lchip]->short_key_boundary[SYS_PRIVATE_MODE]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Short key boundary(Public mode)", p_usw_ipuc_master[lchip]->short_key_boundary[SYS_PUBLIC_MODE]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Tcam share mode(Private mode)", p_usw_ipuc_master[lchip]->tcam_share_mode[SYS_PRIVATE_MODE]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Tcam share mode(Public mode)", p_usw_ipuc_master[lchip]->tcam_share_mode[SYS_PUBLIC_MODE]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Share ofb type(Private mode)", p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PRIVATE_MODE]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Share ofb type(Public mode)", p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PUBLIC_MODE]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: 0x%x\n", "IPv4 Lookup mode", p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: 0x%x\n", "IPv6 Lookup mode", p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_6]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv4 enable", p_usw_ipuc_master[lchip]->version_en[CTC_IP_VER_4]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv6 enable", p_usw_ipuc_master[lchip]->version_en[CTC_IP_VER_6]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Host lpm mode", p_usw_ipuc_master[lchip]->host_lpm_mode);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Prefix 64 mode", p_usw_ipuc_master[lchip]->prefix64_mode);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv4 lpm tcam spec", p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_4]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv6 lpm tcam spec", p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_6]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv4 lpm tcam used", p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[CTC_IP_VER_4]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv6 lpm tcam used", p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[CTC_IP_VER_6]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv4 auto resolve conflict use tcam", p_usw_ipuc_master[lchip]->arc[CTC_IP_VER_4]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "IPv6 auto resolve conflict use tcam", p_usw_ipuc_master[lchip]->arc[CTC_IP_VER_6]);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Total snake number", p_usw_ipuc_master[lchip]->max_size_of_snake);
    cmd = DRV_IOR(DsRpf_t, DsRpf_moreRpfCheckMode_f);
    CTC_ERROR_RETURN_IPUC_UNLOCK(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &value));
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Rpf action", value);
    SYS_DUMP_DB_LOG(p_f, "%-40s: %u\n", "Rpf check port", p_usw_ipuc_master[lchip]->rpf_check_port);
    SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    if(p_dump_param->detail)
    {
        SYS_DUMP_DB_LOG(p_f, "Spool type: %s\n","ad_spool(DsIpDa)");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%-10s%-10s%-10s%-10s\n", "Node", "Ref_cnt", "Ad_index", "Data");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        ctc_spool_traverse(p_usw_ipuc_master[lchip]->ad_spool, (spool_traversal_fn)_sys_usw_ipuc_ad_fprintf_traverse , (void*)(&cb_data));
    }
    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_LOOKUP))
    {
        sys_usw_ofb_dump_db(lchip, p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PRIVATE_MODE], p_f);
    }
    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP))
    {
        sys_usw_ofb_dump_db(lchip, p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PUBLIC_MODE], p_f);
    }

    if(p_usw_ipuc_master[lchip]->multi_level &&MCHIP_IPUC(lchip)->nalpm2_dump_db)
    {
        MCHIP_IPUC(lchip)->nalpm2_dump_db(lchip, p_f, p_dump_param);
    }
    else if(MCHIP_IPUC(lchip)->alpm_dump_db)
    {
        MCHIP_IPUC(lchip)->alpm_dump_db(lchip, p_f, p_dump_param);
    }

    if (MCHIP_IPUC(lchip)->show_tcam_status)
    {
        MCHIP_IPUC(lchip)->show_tcam_status(lchip, p_f);
    }
    SYS_DUMP_DB_LOG(p_f, "%s\n", "}");
    SYS_IPUC_UNLOCK;
    return ret;
}

#define __2_OTHER__


int32
sys_usw_ipuc_wb_sync(uint8 lchip,uint32 app_id)
{
    uint32 cmd = 0;
    int32 ret = CTC_E_NONE;
    ctc_wb_data_t wb_data;
    sys_wb_ipuc_master_t  *p_wb_ipuc_master;
    uint32 field_val = 0;

    SYS_IPUC_INIT_CHECK;

    CTC_WB_ALLOC_BUFFER(&wb_data.buffer);
    SYS_IPUC_LOCK;
    if (app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_IPUC_SUBID_MASTER)
    {
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_ipuc_master_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_MASTER);

        p_wb_ipuc_master = (sys_wb_ipuc_master_t  *)wb_data.buffer;

        p_wb_ipuc_master->lchip = lchip;
        p_wb_ipuc_master->version = SYS_WB_VERSION_IPUC;
        p_wb_ipuc_master->host_lpm_mode = p_usw_ipuc_master[lchip]->host_lpm_mode;
        p_wb_ipuc_master->prefix64_mode = p_usw_ipuc_master[lchip]->prefix64_mode;
        cmd = DRV_IOR(LpmTcamCtl_t, LpmTcamCtl_privatePublicLookupMode_f);
        DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_val);
        p_wb_ipuc_master->tcam_mode = field_val;
        p_wb_ipuc_master->default_nhid[CTC_IP_VER_4] = p_usw_ipuc_master[lchip]->default_nhid[CTC_IP_VER_4];
        p_wb_ipuc_master->default_nhid[CTC_IP_VER_6] = p_usw_ipuc_master[lchip]->default_nhid[CTC_IP_VER_6];
        p_wb_ipuc_master->lpm_tcam_spec[CTC_IP_VER_4] = p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_4];
        p_wb_ipuc_master->lpm_tcam_spec[CTC_IP_VER_6] = p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_6];
        p_wb_ipuc_master->rsv = 0;

        wb_data.valid_cnt = 1;
        CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
        CTC_WB_SYNC_END_DATA(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_MASTER);
    }
    if (app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_IPUC_SUBID_OFB)
    {
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_ofb_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_OFB);
        if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_LOOKUP))
        {
            CTC_ERROR_GOTO(sys_usw_ofb_wb_sync(lchip, p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PRIVATE_MODE],
                                               CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_OFB, &wb_data), ret, done);
        }
        if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP))
        {
            if(!CTC_WB_DM_MODE(lchip))
            {
                wb_data.valid_cnt = 0;
            }
            CTC_ERROR_GOTO(sys_usw_ofb_wb_sync(lchip, p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PUBLIC_MODE],
                                               CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_OFB, &wb_data), ret, done);
        }
        CTC_WB_SYNC_END_DATA(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_OFB);
    }

    if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        if (MCHIP_IPUC(lchip)->alpm_mapping_wb_master)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->alpm_mapping_wb_master(lchip, 1), ret, done);
        }

        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_wb_set_tcam_index)
        {
            MCHIP_IPUC(lchip)->nalpm2_wb_set_tcam_index(lchip);
        }
        else if (MCHIP_IPUC(lchip)->alpm_wb_set_tcam_index)
        {
            MCHIP_IPUC(lchip)->alpm_wb_set_tcam_index(lchip);
        }
        /*syncup nalpm prefix info*/
        if(p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_wb_prefix_sync)
        {
            ret = MCHIP_IPUC(lchip)->nalpm2_wb_prefix_sync(lchip,app_id, &wb_data);
        }
        else if(MCHIP_IPUC(lchip)->alpm_wb_prefix_sync)
        {
            ret = MCHIP_IPUC(lchip)->alpm_wb_prefix_sync(lchip,app_id, &wb_data);
        }
    }

    if (app_id == 0 || CTC_WB_SUBID(app_id) == SYS_WB_APPID_IPUC_SUBID_INFO)
    {

      sys_traverse_t ipuc_hash_data;
        uint8 ip_ver = 0;
        /*syncup ipuc_info*/
        CTC_WB_INIT_DATA_T((&wb_data), sys_wb_ipuc_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO);
        ipuc_hash_data.data = &wb_data;
        ipuc_hash_data.value1 = lchip;

        
        for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
        {
            if (!p_usw_ipuc_master[lchip]->fib_hash[ip_ver])
            {
                continue;
            }
            CTC_ERROR_GOTO(ctc_hash_traverse(p_usw_ipuc_master[lchip]->fib_hash[ip_ver], (hash_traversal_fn) _sys_usw_ipuc_wb_sync_info_func, (void *)&ipuc_hash_data), ret, done);
        }
        if (wb_data.valid_cnt > 0)
        {
            CTC_ERROR_GOTO(ctc_wb_add_entry(&wb_data), ret, done);
            wb_data.valid_cnt = 0;
        }
        CTC_WB_SYNC_END_DATA(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO);
    }


done:
    SYS_IPUC_UNLOCK;
    CTC_WB_FREE_BUFFER(wb_data.buffer);
    return ret;
}

int32
sys_usw_ipuc_wb_restore(uint8 lchip)
{

    uint32 field_value = 0;
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    ctc_wb_query_t wb_query;
    sys_wb_ipuc_master_t  wb_ipuc_master = {0};
    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);
    CTC_WB_INIT_QUERY_T((&wb_query),sys_wb_ipuc_master_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_MASTER);

    SYS_IPUC_INIT_CHECK;

    CTC_ERROR_GOTO(ctc_wb_query_entry(&wb_query), ret, done);

    /*restore  ipuc_master*/
    if (wb_query.valid_cnt != 1 || wb_query.is_end != 1)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "query ipuc master error! valid_cnt: %d, is_end: %d.\n", wb_query.valid_cnt, wb_query.is_end);
        ret = CTC_E_NONE;
        goto done;
    }

    sal_memcpy((uint8*)&wb_ipuc_master, (uint8*)wb_query.buffer, wb_query.key_len + wb_query.data_len);

    if (CTC_WB_VERSION_CHECK(SYS_WB_VERSION_IPUC, wb_ipuc_master.version))
    {
        ret = CTC_E_VERSION_MISMATCH;
        goto done;
    }

    cmd = DRV_IOR(LpmTcamCtl_t, LpmTcamCtl_privatePublicLookupMode_f);
    DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value);

     if ((field_value !=  wb_ipuc_master.tcam_mode) ||
        (p_usw_ipuc_master[lchip]->host_lpm_mode != wb_ipuc_master.host_lpm_mode) ||
        (p_usw_ipuc_master[lchip]->prefix64_mode != wb_ipuc_master.prefix64_mode))
    {
        ret = CTC_E_VERSION_MISMATCH;
       SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR,
           "ipuc init and warmboot tcam mode mismatch! tcam mode: %u|%u use lpm enable: %u|%u  prefix64_mode:%d|%d\n",
            field_value, wb_ipuc_master.tcam_mode,
            p_usw_ipuc_master[lchip]->host_lpm_mode, wb_ipuc_master.host_lpm_mode,
            p_usw_ipuc_master[lchip]->prefix64_mode , wb_ipuc_master.prefix64_mode);

        goto done;
    }

    p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_4] = wb_ipuc_master.lpm_tcam_spec[CTC_IP_VER_4];
    p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_6] = wb_ipuc_master.lpm_tcam_spec[CTC_IP_VER_6];

    cmd = DRV_IOR(FibEngineLookupResultCtl_t, FibEngineLookupResultCtl_gIpv4UcastLookupResultCtl_defaultEntryBase_f);
    DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &p_usw_ipuc_master[lchip]->default_base[CTC_IP_VER_4]);

    cmd = DRV_IOR(FibEngineLookupResultCtl_t, FibEngineLookupResultCtl_gIpv6UcastLookupResultCtl_defaultEntryBase_f);
    DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &p_usw_ipuc_master[lchip]->default_base[CTC_IP_VER_6]);
    
    cmd = DRV_IOR(DsIpDa_t,DsIpDa_isCtcDefaultRoute_f);
    DRV_FIELD_IOCTL(lchip, p_usw_ipuc_master[lchip]->default_base[CTC_IP_VER_4], DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)),&field_value);
    p_usw_ipuc_master[lchip]->rpf_permit_default_en = field_value ? 0 : 1;

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_LOOKUP))
    {
        CTC_ERROR_GOTO(sys_usw_ofb_wb_restore(lchip, p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PRIVATE_MODE],
                                            CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_OFB), ret, done);
    }

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP))
    {
        CTC_ERROR_GOTO(sys_usw_ofb_wb_restore(lchip, p_usw_ipuc_master[lchip]->share_ofb_type[SYS_PUBLIC_MODE],
                                        CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_OFB), ret, done);
    }
    p_usw_ipuc_master[lchip]->default_nhid[CTC_IP_VER_4] = wb_ipuc_master.default_nhid[CTC_IP_VER_4];
    p_usw_ipuc_master[lchip]->default_nhid[CTC_IP_VER_6] = wb_ipuc_master.default_nhid[CTC_IP_VER_6];

    /*restore nalpm prefix info*/
    if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        if (MCHIP_IPUC(lchip)->alpm_mapping_wb_master)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->alpm_mapping_wb_master(lchip, 0), ret, done);
        }

        if(p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_wb_prefix_restore)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->nalpm2_wb_prefix_restore(lchip),ret,done);
        }
        else if(MCHIP_IPUC(lchip)->alpm_wb_prefix_restore)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->alpm_wb_prefix_restore(lchip),ret,done);
        }
    }

    /*restore  ipuc_info*/
    if(ctc_wb_get_rt_en(lchip,CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO))
    {
         _sys_usw_ipuc_restore_ipuc_info2( lchip);
    }
    else
     {
          _sys_usw_ipuc_restore_ipuc_info( lchip);
     }
done:
   CTC_WB_FREE_BUFFER(wb_query.buffer);
    return ret;
}

int32
sys_usw_ipuc_set_route_spec(uint8 lchip, uint32 v4_spec, uint32 v6_spec)
{
    uint32 entry_num_v4 = 0;
    uint32 entry_num_v6_single = 0;
    uint32 entry_num_v6_double = 0;
    uint32 all = 0;

    SYS_IPUC_INIT_CHECK;

    SYS_IPUC_LOCK;
    entry_num_v4 = p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM];
    entry_num_v6_single = p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT];
    entry_num_v6_double = p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM];
    if(entry_num_v6_double && (v6_spec%4 != 0))
    {
        SYS_IPUC_UNLOCK;
        return CTC_E_INVALID_PARAM;
    }
    if(entry_num_v6_single && !entry_num_v6_double && (v6_spec%2 != 0))
    {
        SYS_IPUC_UNLOCK;
        return CTC_E_INVALID_PARAM;
    }

    all = entry_num_v4 + entry_num_v6_single + entry_num_v6_double;
    if (v4_spec > all || v6_spec > all)
    {
        SYS_IPUC_UNLOCK;
        return CTC_E_INVALID_PARAM;
    }
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_MASTER, 1);
    if(!v4_spec && !v6_spec)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_4] = entry_num_v4;
        p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_6] = entry_num_v6_single + entry_num_v6_double;
    }
    if(v4_spec)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_4] = v4_spec;
    }
    if(v6_spec)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_6] = v6_spec;
    }

    if(!v4_spec)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_4] = all - v6_spec;/*v6_spec musn`t be 0*/
    }

    if(!v6_spec)
    {
        if (entry_num_v6_double)
        {
            v6_spec = (all - v4_spec) / 4 * 4;
        }
        else
        {
            v6_spec = (all - v4_spec) / 2 * 2;
        }
        p_usw_ipuc_master[lchip]->lpm_tcam_spec[CTC_IP_VER_6] = v6_spec;/*v4_spec musn`t be 0*/
    }

    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_get_nalpm_level_info(uint8 lchip, uint8* level)
{
    SYS_IPUC_INIT_CHECK;
    *level = p_usw_ipuc_master[lchip]->multi_level;
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_set_rpf_fail_to_cpu(uint8 lchip ,uint8 enable)
{
    uint32 cmd = 0;
    uint16 loop_i = 0;
    uint32 field_value = 0;

    SYS_IPUC_INIT_CHECK;
    SYS_IPUC_LOCK;

    cmd = DRV_IOW(DsRpf_t, DsRpf_moreRpfCheckMode_f);
    field_value = enable? 2 : 0;  /*moreRpfCheckMode = 2 means rpf fail will copy to cpu and not drop*/
    for(loop_i = 0 ;loop_i < DRV_TABLE_MAX_INDEX(lchip, DsRpf_t); loop_i++)
    {
        CTC_ERROR_RETURN_IPUC_UNLOCK(DRV_FIELD_IOCTL(lchip, loop_i, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));
    }

    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

int32
sys_usw_ipuc_init(uint8 lchip, ctc_ipuc_global_cfg_t* p_ipuc_global_cfg)
{
    uint8 ipsa_enable = 0;
    uint16 loop_i = 0;
    int32  ret = 0;
    uint32 cmd = 0;
    uint32 field_value = 0;
    ds_t fib_engine_lookup_ctl;
    uint64 cpu_mask = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    sal_memset(&fib_engine_lookup_ctl, 0, sizeof(fib_engine_lookup_ctl));

    if(NULL != p_usw_ipuc_master[lchip])
    {
        return CTC_E_NONE;
    }
    CTC_MAX_VALUE_CHECK(p_ipuc_global_cfg->host_use_lpm, 2);
    CTC_MAX_VALUE_CHECK(p_ipuc_global_cfg->prefix64_mode, 3);

    LCHIP_CHECK(lchip);

    if (SYS_VCHIP_PP_IS_NOT_BASE(lchip) && !MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC))
    {
        (p_usw_ipuc_master)[lchip] = (p_usw_ipuc_master)[drv_vchip_get_pp_base(lchip)];
        (g_sys_nalpm_master)[lchip] = (g_sys_nalpm_master)[drv_vchip_get_pp_base(lchip)];
        return CTC_E_NONE;
    }
    CTC_ERROR_RETURN(sys_usw_ip_tunnel_init(lchip, p_ipuc_global_cfg->napt_port_disable));

    if(p_ipuc_global_cfg->master_lchip_valid && p_ipuc_global_cfg->master_lchip != lchip)
    {
        ret = _sys_usw_ipuc_init_slave(lchip, p_ipuc_global_cfg);
        if (ret)
        {
            goto error0;
        }
        return ret;
    }

    p_usw_ipuc_master[lchip] = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_ipuc_master_t), sys_ipuc_master_t);
    if (NULL == p_usw_ipuc_master[lchip])
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        CTC_ERROR_RETURN(CTC_E_NO_MEMORY);
    }
    sal_memset(p_usw_ipuc_master[lchip], 0, sizeof(sys_ipuc_master_t));

    sal_mutex_create(&p_usw_ipuc_master[lchip]->mutex);
    if (NULL == p_usw_ipuc_master[lchip]->mutex)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        ret = CTC_E_NO_MEMORY;
        goto error1;
    }

    sal_mutex_create(&p_usw_ipuc_master[lchip]->lpm_mutex);
    if (NULL == p_usw_ipuc_master[lchip]->lpm_mutex)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " No memory \n");
        ret = CTC_E_NO_MEMORY;
        goto error1;
    }
    p_usw_ipuc_master[lchip]->slave_lchip_cnt = 1;
    p_usw_ipuc_master[lchip]->master_lchip = lchip;
    p_usw_ipuc_master[lchip]->host_lpm_mode = p_ipuc_global_cfg->host_use_lpm;
    p_usw_ipuc_master[lchip]->prefix64_mode= p_ipuc_global_cfg->prefix64_mode;
    p_usw_ipuc_master[lchip]->callback = p_ipuc_global_cfg->callback;
    p_usw_ipuc_master[lchip]->user_data = p_ipuc_global_cfg->user_data;
    p_usw_ipuc_master[lchip]->rpf_check_port = p_ipuc_global_cfg->rpf_check_port ? 1 : 0;

    p_usw_ipuc_master[lchip]->ipuc_position_add[DO_HASH] = _sys_usw_ipuc_add_hash;
    p_usw_ipuc_master[lchip]->ipuc_position_add[DO_TCAM] = _sys_usw_ipuc_add_tcam;
    p_usw_ipuc_master[lchip]->ipuc_position_add[DO_ALPM] = _sys_usw_ipuc_add_alpm;

    p_usw_ipuc_master[lchip]->use_snake64 = (p_usw_ipuc_master[lchip]->prefix64_mode == CTC_IPUC_SHORT_V6_PREFIX_MODE || p_usw_ipuc_master[lchip]->prefix64_mode == 3);

    CTC_ERROR_GOTO(_sys_usw_ipuc_resource_init(lchip), ret, error2);
    if ((p_usw_ipuc_master[lchip]->version_en[CTC_IP_VER_4] + p_usw_ipuc_master[lchip]->version_en[CTC_IP_VER_6]) == 0)
    {
        /* no resource for ipuc, not init ipuc */
        ret= CTC_E_NOT_SUPPORT;
        goto error2;
    }

    CTC_ERROR_GOTO(sys_usw_ipuc_db_init(lchip), ret, error3);

    cmd = DRV_IOR(FibEngineLookupCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &fib_engine_lookup_ctl), ret, error3);

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP))
    {
        SetFibEngineLookupCtl(V, privatePublicLookupModeEn_f, fib_engine_lookup_ctl, 1);    /* set public lookup */
    }

    SetFibEngineLookupCtl(V, hostUrpfEn_f, fib_engine_lookup_ctl, 1);    /*neighbor route support rpf*/

    cmd = DRV_IOR(FibNeoLpmCtl_t, FibNeoLpmCtl_multiLevelEn_f);
    CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));
    p_usw_ipuc_master[lchip]->multi_level = field_value;

    /* calpm must init before tcam init, because tcam block init need calpm prefix mode*/
    if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        ipsa_enable = CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_SA_LOOKUP);

        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_init)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->nalpm2_init(lchip, p_ipuc_global_cfg, ipsa_enable), ret, error3);
            SetFibEngineLookupCtl(V, lpmPipelineEn_f, fib_engine_lookup_ctl, 1);
        }
        else if (MCHIP_IPUC(lchip)->alpm_init)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->alpm_init(lchip, p_ipuc_global_cfg, ipsa_enable), ret, error3);
            SetFibEngineLookupCtl(V, lpmPipelineEn_f, fib_engine_lookup_ctl, 1);
        }
    }

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_LOOKUP))
    {
        if (MCHIP_IPUC(lchip)->tcam_init)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->tcam_init(lchip, SYS_PRIVATE_MODE, MCHIP_IPUC(lchip)->tcam_move_cb), ret, error4);
        }
    }

    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP))
    {
        if (MCHIP_IPUC(lchip)->tcam_init)
        {
            CTC_ERROR_GOTO(MCHIP_IPUC(lchip)->tcam_init(lchip, SYS_PUBLIC_MODE, MCHIP_IPUC(lchip)->tcam_move_cb), ret, error5);
        }
    }

    cmd = DRV_IOW(FibEngineLookupCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_GOTO(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &fib_engine_lookup_ctl), ret, error6);

    cmd = DRV_IOW(IpeRouteCtl_t, IpeRouteCtl_rpfCheckAgainstPort_f);
    field_value = p_ipuc_global_cfg->rpf_check_port;
    CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value), ret, error6);

    cmd = DRV_IOW(DsRpf_t, DsRpf_moreRpfCheckMode_f);
    field_value = p_ipuc_global_cfg->rpf_fail_to_cpu ? 2 : 0;
    for(loop_i = 0 ;loop_i < DRV_TABLE_MAX_INDEX(lchip, DsRpf_t); loop_i++)
    {
        CTC_ERROR_GOTO(DRV_FIELD_IOCTL(lchip, loop_i, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value), ret, error6);
    }

    /*init ipuc related register*/
    CTC_ERROR_GOTO(_sys_usw_ipuc_init_register(lchip),ret,error6);


    p_usw_ipuc_master[lchip]->arc[CTC_IP_VER_4] = (p_usw_ipuc_master[lchip]->host_lpm_mode != 2)?1:0;
    p_usw_ipuc_master[lchip]->arc[CTC_IP_VER_6] = (p_usw_ipuc_master[lchip]->host_lpm_mode != 2)?((p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM] ==0) ? 0 : 1):0;

    if (CTC_WB_ENABLE(lchip) && (CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING))
    {
        cmd = DRV_IOR(IpeRouteCtl_t, IpeRouteCtl_rpfCheckAgainstPort_f);
        CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &field_value));
        if (field_value != p_ipuc_global_cfg->rpf_check_port)
        {
            ret = CTC_E_INVALID_PARAM;
            goto error6;
        }
        p_usw_ipuc_master[lchip]->rpf_check_port = field_value;
    }

    /*init default entry*/
    p_usw_ipuc_master[lchip]->default_route_mode = p_ipuc_global_cfg->default_route_mode? 1 : 0;
    CTC_ERROR_GOTO(_sys_usw_ipuc_init_default_entry(lchip),ret,error6);

    sys_usw_ftm_register_callback(lchip, CTC_FTM_SPEC_IPUC_HOST,
                sys_usw_ipuc_host_ftm_cb);
    sys_usw_ftm_register_callback(lchip, CTC_FTM_SPEC_IPUC_LPM,
                sys_usw_ipuc_alpm_ftm_cb);

    CTC_ERROR_GOTO(sys_usw_wb_sync_register_cb(lchip, CTC_FEATURE_IPUC,SYS_WB_APPID_IPUC_SUBID_MAX, sys_usw_ipuc_wb_sync), ret, error6);

    if (CTC_WB_ENABLE(lchip) )
    {
       if( CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
       {
           CTC_ERROR_GOTO(sys_usw_ipuc_wb_restore(lchip), ret, error6);
       }
       _sys_usw_ipuc_wb_init(lchip);
    }

    /*update main thread*/
    cpu_mask = sys_usw_chip_get_affinity(lchip, 0);
    if (cpu_mask)
    {
        if(ctc_sal_task_set_affinity_prio(0, cpu_mask, 0) < 0)
        {
            ret = CTC_E_INIT_FAIL;
            goto error6;
        }
    }
    if (!DRV_IS_DUET2(lchip))
    {
        uint32 entry_num = 0;
        CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsNeoLpmIpv4Bit32Snake_t, &entry_num));
        p_usw_ipuc_master[lchip]->max_size_of_snake = entry_num;
    }
    CTC_ERROR_GOTO(sys_usw_dump_db_register_cb(lchip, CTC_FEATURE_IPUC, sys_usw_ipuc_dump_db), ret, error6);
    #ifdef CTC_WB_RT_SYNC
    CTC_ERROR_GOTO(SYS_CB_REGISTER(lchip, SYS_CB_IPUC_UPDATE_HASH, _sys_usw_ipuc_update_hash), ret, error6);
    #endif
    sys_usw_mchip_set_feature_en(lchip,CTC_FEATURE_IPUC);
    return CTC_E_NONE;

error6:
    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_PUB_LOOKUP))
    {
        if (MCHIP_IPUC(lchip)->tcam_deinit)
        {
            MCHIP_IPUC(lchip)->tcam_deinit(lchip, SYS_PUBLIC_MODE);
        }
    }

error5:
    if (CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_LOOKUP))
    {
        if (MCHIP_IPUC(lchip)->tcam_deinit)
        {
            MCHIP_IPUC(lchip)->tcam_deinit(lchip, SYS_PRIVATE_MODE);
        }
    }

error4:
    if(CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_ALPM_LOOKUP))
    {
        ipsa_enable = CTC_FLAG_ISSET(p_usw_ipuc_master[lchip]->lookup_mode[CTC_IP_VER_4], SYS_TCAM_SA_LOOKUP);

        if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_deinit)
        {
            MCHIP_IPUC(lchip)->nalpm2_deinit(lchip);
        }
        else if (MCHIP_IPUC(lchip)->alpm_deinit)
        {
            MCHIP_IPUC(lchip)->alpm_deinit(lchip);
        }
    }

error3:
    sys_usw_ipuc_db_deinit(lchip);

error2:
    if (p_usw_ipuc_master[lchip]->mutex)
    {
        sal_mutex_destroy(p_usw_ipuc_master[lchip]->mutex);
    }
    if (p_usw_ipuc_master[lchip]->lpm_mutex)
    {
        sal_mutex_destroy(p_usw_ipuc_master[lchip]->lpm_mutex);
    }

error1:
    mem_free(p_usw_ipuc_master[lchip]);
error0:
    sys_usw_ip_tunnel_deinit(lchip);

    return ret;
}

int32
sys_usw_ipuc_deinit(uint8 lchip)
{
    uint8 loop_lchip = 0;

    LCHIP_CHECK(lchip);
    if (NULL == p_usw_ipuc_master[lchip])
    {
        return CTC_E_NONE;
    }

    if (SYS_VCHIP_PP_IS_NOT_BASE(lchip) && !MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC))
    {
        (p_usw_ipuc_master)[lchip] = NULL;
        (g_sys_nalpm_master)[lchip] = NULL;
        return CTC_E_NONE;
    }


    sys_usw_wb_sync_register_cb(lchip, CTC_FEATURE_IPUC,0, NULL);
    SYS_CB_REGISTER(lchip, SYS_CB_IPUC_UPDATE_HASH, NULL);

    if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_deinit)
    {
        MCHIP_IPUC(lchip)->nalpm2_deinit(lchip);
    }
    else if (MCHIP_IPUC(lchip)->alpm_deinit)
    {
        MCHIP_IPUC(lchip)->alpm_deinit(lchip);
    }

    sys_usw_ip_tunnel_deinit(lchip);
    if(lchip != p_usw_ipuc_master[lchip]->master_lchip)
    {
        (p_usw_ipuc_master)[lchip] = NULL;
        return CTC_E_NONE;
    }

    if(p_usw_ipuc_master[lchip]->slave_lchip_cnt > 1)
    {
        for(loop_lchip = 1; loop_lchip < p_usw_ipuc_master[lchip]->slave_lchip_cnt; loop_lchip++)
        {
            sys_usw_ip_tunnel_deinit(lchip + (loop_lchip * SYS_PP_NUM(lchip)));
            if (p_usw_ipuc_master[lchip]->multi_level && MCHIP_IPUC(lchip)->nalpm2_deinit)
            {
                MCHIP_IPUC(lchip)->nalpm2_deinit(lchip + (loop_lchip * SYS_PP_NUM(lchip)));
            }
            else if (MCHIP_IPUC(lchip)->alpm_deinit)
            {
                MCHIP_IPUC(lchip)->alpm_deinit(lchip + (loop_lchip * SYS_PP_NUM(lchip)));
            }
            (p_usw_ipuc_master)[lchip + (loop_lchip * SYS_PP_NUM(lchip))] = NULL;
        }
    }

    sys_usw_ipuc_db_deinit(lchip);

    if (MCHIP_IPUC(lchip)->tcam_deinit)
    {
        MCHIP_IPUC(lchip)->tcam_deinit(lchip, SYS_PRIVATE_MODE);
        MCHIP_IPUC(lchip)->tcam_deinit(lchip, SYS_PUBLIC_MODE);
    }

    if (p_usw_ipuc_master[lchip]->mutex)
    {
        sal_mutex_destroy(p_usw_ipuc_master[lchip]->mutex);
    }

    if (p_usw_ipuc_master[lchip]->lpm_mutex)
    {
        sal_mutex_destroy(p_usw_ipuc_master[lchip]->lpm_mutex);
    }

    mem_free(p_usw_ipuc_master[lchip]);

    return CTC_E_NONE;
}
#endif
